Compare commits

..

17 Commits

Author SHA1 Message Date
William Woodall
36ca813813 another wip
Signed-off-by: William Woodall <william@osrfoundation.org>
2019-02-04 14:28:03 -08:00
William Woodall
8f0705b08b style
Signed-off-by: William Woodall <william@osrfoundation.org>
2019-02-04 10:21:37 -08:00
William Woodall
2e32bc300c provide implementation for templated declare_parameter method
Signed-off-by: William Woodall <william@osrfoundation.org>
2019-02-01 11:14:31 -08:00
William Woodall
7e5e75a748 replace create_parameter with declare_parameter
Signed-off-by: William Woodall <william@osrfoundation.org>
2019-02-01 09:18:49 -08:00
William Woodall
c94a1bf286 more fixup after rebase
Signed-off-by: William Woodall <william@osrfoundation.org>
2019-02-01 09:16:57 -08:00
William Woodall
17b3b971b3 fixup after rebase
Signed-off-by: William Woodall <william@osrfoundation.org>
2019-02-01 09:16:54 -08:00
William Woodall
c026f89650 match type of enum in C++ to type used in message definition
Signed-off-by: William Woodall <william@osrfoundation.org>
2019-01-29 11:05:30 -08:00
William Woodall
1eecfe73cc avoid const pass by value
Signed-off-by: William Woodall <william@osrfoundation.org>
2019-01-29 11:05:30 -08:00
William Woodall
2e20bcb844 enable get<Parameter> and get<ParameterValue> on Parameter class
Signed-off-by: William Woodall <william@osrfoundation.org>
2019-01-29 11:05:30 -08:00
William Woodall
be9f07a414 add method to access ParameterValue within a Parameter
Signed-off-by: William Woodall <william@osrfoundation.org>
2019-01-29 11:05:30 -08:00
William Woodall
3f344549b9 rename ParameterInfo_t to ParameterInfo and just use struct, no typedef
Signed-off-by: William Woodall <william@osrfoundation.org>
2019-01-29 11:05:30 -08:00
William Woodall
58fd8edee1 use override rather than virtual in places
Signed-off-by: William Woodall <william@osrfoundation.org>
2019-01-29 11:05:30 -08:00
William Woodall
b0ac4453a3 doc fixup
Signed-off-by: William Woodall <william@osrfoundation.org>
2019-01-29 11:04:57 -08:00
Shane Loretz
3845f03d8a Only get parameter if it is set 2019-01-29 11:04:57 -08:00
Shane Loretz
6651abcbe9 test undeclared params 2019-01-29 11:04:57 -08:00
Shane Loretz
e86de20b7a style 2019-01-29 11:04:57 -08:00
Shane Loretz
bf03325e0a in progress broken test_time_source 2019-01-29 11:04:53 -08:00
151 changed files with 2733 additions and 11806 deletions

View File

@@ -11,8 +11,3 @@ be under the Apache 2 License, as dictated by that
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
~~~
Contributors must sign-off each commit by adding a `Signed-off-by: ...`
line to commit messages to certify that they have the right to submit
the code they are contributing to the project according to the
[Developer Certificate of Origin (DCO)](https://developercertificate.org/).

View File

@@ -2,72 +2,6 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
0.7.2 (2019-05-08)
------------------
* Added new way to specify QoS settings for publishers and subscriptions. (`#713 <https://github.com/ros2/rclcpp/issues/713>`_)
* The new way requires that you specify a history depth when creating a publisher or subscription.
* In the past it was possible to create one without specifying any history depth, but these signatures have been deprecated.
* Deprecated ``shared_ptr`` and raw pointer versions of ``Publisher<T>::publish()``. (`#709 <https://github.com/ros2/rclcpp/issues/709>`_)
* Implemented API to set callbacks for liveliness and deadline QoS events for publishers and subscriptions. (`#695 <https://github.com/ros2/rclcpp/issues/695>`_)
* Fixed a segmentation fault when publishing a parameter event when they ought to be disabled. (`#714 <https://github.com/ros2/rclcpp/issues/714>`_)
* Changes required for upcoming pre-allocation API. (`#711 <https://github.com/ros2/rclcpp/issues/711>`_)
* Changed ``Node::get_node_names()`` to return the full node names rather than just the base name. (`#698 <https://github.com/ros2/rclcpp/issues/698>`_)
* Remove logic made redundant by the `ros2/rcl#255 <https://github.com/ros2/rcl/issues/255>`_ pull request. (`#712 <https://github.com/ros2/rclcpp/issues/712>`_)
* Various improvements for ``rclcpp::Clock``. (`#696 <https://github.com/ros2/rclcpp/issues/696>`_)
* Fixed uninitialized bool in ``clock.cpp``.
* Fixed up includes of ``clock.hpp/cpp``.
* Added documentation for exceptions to ``clock.hpp``.
* Adjusted function signature of getters of ``clock.hpp/cpp``.
* Removed raw pointers to ``Clock::create_jump_callback``.
* Removed unnecessary ``rclcpp`` namespace reference from ``clock.cpp``.
* Changed exception to ``bad_alloc`` on ``JumpHandler`` allocation failure.
* Fixed missing ``nullptr`` check in ``Clock::on_time_jump``.
* Added ``JumpHandler::callback`` types.
* Added warning for lifetime of Clock and JumpHandler
* Fixed bug left over from the `pull request #495 <https://github.com/ros2/rclcpp/pull/495>`_. (`#708 <https://github.com/ros2/rclcpp/issues/708>`_)
* Changed the ``IntraProcessManager`` to be capable of storing ``shared_ptr<const T>`` in addition to ``unique_ptr<T>``. (`#690 <https://github.com/ros2/rclcpp/issues/690>`_)
* Contributors: Alberto Soragna, Dima Dorezyuk, M. M, Michael Carroll, Michael Jeronimo, Tully Foote, William Woodall, ivanpauno, jhdcs
0.7.1 (2019-04-26)
------------------
* Added read only parameters. (`#495 <https://github.com/ros2/rclcpp/issues/495>`_)
* Fixed a concurrency problem in the multithreaded executor. (`#703 <https://github.com/ros2/rclcpp/issues/703>`_)
* Fixup utilities. (`#692 <https://github.com/ros2/rclcpp/issues/692>`_)
* Added method to read timer cancellation. (`#697 <https://github.com/ros2/rclcpp/issues/697>`_)
* Added Exception Generator function for implementing "from_rcl_error". (`#678 <https://github.com/ros2/rclcpp/issues/678>`_)
* Updated initialization of rmw_qos_profile_t struct instances. (`#691 <https://github.com/ros2/rclcpp/issues/691>`_)
* Removed the const value from the logger before comparison. (`#680 <https://github.com/ros2/rclcpp/issues/680>`_)
* Contributors: Devin Bonnie, Dima Dorezyuk, Guillaume Autran, M. M, Shane Loretz, Víctor Mayoral Vilches, William Woodall, jhdcs
0.7.0 (2019-04-14)
------------------
* Added Options-struct interfaces for creating publishers/subscribers (pre-QoS, standalone). (`#673 <https://github.com/ros2/rclcpp/issues/673>`_)
* Replaced strncpy with memcpy. (`#684 <https://github.com/ros2/rclcpp/issues/684>`_)
* Replaced const char * with a std::array<char, TOPIC_NAME_LENGTH> as the key of IPM IDTopicMap. (`#671 <https://github.com/ros2/rclcpp/issues/671>`_)
* Refactored SignalHandler logger to avoid race during destruction. (`#682 <https://github.com/ros2/rclcpp/issues/682>`_)
* Introduce rclcpp_components to implement composition. (`#665 <https://github.com/ros2/rclcpp/issues/665>`_)
* Added QoS policy check when configuring intraprocess, skip interprocess publish when possible. (`#674 <https://github.com/ros2/rclcpp/issues/674>`_)
* Updated to use do { .. } while(0) around content of logging macros. (`#681 <https://github.com/ros2/rclcpp/issues/681>`_)
* Added function to get publisher's actual QoS settings. (`#667 <https://github.com/ros2/rclcpp/issues/667>`_)
* Updated to avoid race that triggers timer too often. (`#621 <https://github.com/ros2/rclcpp/issues/621>`_)
* Exposed get_fully_qualified_name in NodeBase API. (`#662 <https://github.com/ros2/rclcpp/issues/662>`_)
* Updated to use ament_target_dependencies where possible. (`#659 <https://github.com/ros2/rclcpp/issues/659>`_)
* Fixed wait for service memory leak bug. (`#656 <https://github.com/ros2/rclcpp/issues/656>`_)
* Fixed test_time_source test. (`#639 <https://github.com/ros2/rclcpp/issues/639>`_)
* Fixed hard-coded duration type representation so int64_t isn't assumed. (`#648 <https://github.com/ros2/rclcpp/issues/648>`_)
* Fixed cppcheck warning. (`#646 <https://github.com/ros2/rclcpp/issues/646>`_)
* Added count matching api and intra-process subscriber count. (`#628 <https://github.com/ros2/rclcpp/issues/628>`_)
* Added Sub Node alternative. (`#581 <https://github.com/ros2/rclcpp/issues/581>`_)
* Replaced 'auto' with 'const auto &'. (`#630 <https://github.com/ros2/rclcpp/issues/630>`_)
* Set Parameter Event Publisher settings. `#591 <https://github.com/ros2/rclcpp/issues/591>`_ (`#614 <https://github.com/ros2/rclcpp/issues/614>`_)
* Replaced node constructor arguments with NodeOptions. (`#622 <https://github.com/ros2/rclcpp/issues/622>`_)
* Updated to pass context to wait set (`#617 <https://github.com/ros2/rclcpp/issues/617>`_)
* Added API to get parameters in a map. (`#575 <https://github.com/ros2/rclcpp/issues/575>`_)
* Updated Bind usage since it is is no longer in std::__1. (`#618 <https://github.com/ros2/rclcpp/issues/618>`_)
* Fixed errors from uncrustify v0.68. (`#613 <https://github.com/ros2/rclcpp/issues/613>`_)
* Added new constructors for SyncParameterClient. (`#612 <https://github.com/ros2/rclcpp/issues/612>`_)
* Contributors: Alberto Soragna, Chris Lalancette, Dirk Thomas, Emerson Knapp, Francisco Martín Rico, Jacob Perron, Marko Durkovic, Michael Carroll, Peter Baughman, Shane Loretz, Wei Liu, William Woodall, Yutaka Kondo, ivanpauno, kuzai, rarvolt
0.6.2 (2018-12-13)
------------------
* Updated to use signal safe synchronization with platform specific semaphores (`#607 <https://github.com/ros2/rclcpp/issues/607>`_)

View File

@@ -47,7 +47,6 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/memory_strategies.cpp
src/rclcpp/memory_strategy.cpp
src/rclcpp/node.cpp
src/rclcpp/node_options.cpp
src/rclcpp/node_interfaces/node_base.cpp
src/rclcpp/node_interfaces/node_clock.cpp
src/rclcpp/node_interfaces/node_graph.cpp
@@ -64,12 +63,10 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/parameter_events_filter.cpp
src/rclcpp/parameter_map.cpp
src/rclcpp/parameter_service.cpp
src/rclcpp/publisher_base.cpp
src/rclcpp/qos.cpp
src/rclcpp/qos_event.cpp
src/rclcpp/publisher.cpp
src/rclcpp/service.cpp
src/rclcpp/signal_handler.cpp
src/rclcpp/subscription_base.cpp
src/rclcpp/subscription.cpp
src/rclcpp/time.cpp
src/rclcpp/time_source.cpp
src/rclcpp/timer.cpp
@@ -85,40 +82,19 @@ configure_file(
COPYONLY
)
# generate header with logging macros
set(python_code_logging
set(python_code
"import em"
"em.invoke(['-o', 'include/rclcpp/logging.hpp', '${CMAKE_CURRENT_SOURCE_DIR}/resource/logging.hpp.em'])")
string(REPLACE ";" "$<SEMICOLON>" python_code_logging "${python_code_logging}")
string(REPLACE ";" "$<SEMICOLON>" python_code "${python_code}")
add_custom_command(OUTPUT include/rclcpp/logging.hpp
COMMAND ${CMAKE_COMMAND} -E make_directory "include/rclcpp"
COMMAND ${PYTHON_EXECUTABLE} ARGS -c "${python_code_logging}"
COMMAND ${PYTHON_EXECUTABLE} ARGS -c "${python_code}"
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/logging.hpp.em.watch"
COMMENT "Expanding logging.hpp.em"
VERBATIM
)
list(APPEND ${PROJECT_NAME}_SRCS
include/rclcpp/logging.hpp)
# "watch" template for changes
configure_file(
"resource/interface_traits.hpp.em"
"interface_traits.hpp.em.watch"
COPYONLY
)
set(python_code_interface_traits
"import em"
"em.invoke(['-o', 'include/rclcpp/node_interfaces/interface_traits.hpp', '${CMAKE_CURRENT_SOURCE_DIR}/resource/interface_traits.hpp.em'])")
string(REPLACE ";" "$<SEMICOLON>" python_code_interface_traits "${python_code_interface_traits}")
add_custom_command(OUTPUT include/rclcpp/node_interfaces/interface_traits.hpp
COMMAND ${CMAKE_COMMAND} -E make_directory "include/rclcpp/node_interfaces"
COMMAND ${PYTHON_EXECUTABLE} ARGS -c "${python_code_interface_traits}"
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/interface_traits.hpp.em.watch"
COMMENT "Expanding interfae_traits.hpp.em"
VERBATIM
)
list(APPEND ${PROJECT_NAME}_SRCS
include/rclcpp/node_interfaces/interface_traits.hpp)
include_directories("${CMAKE_CURRENT_BINARY_DIR}/include")
add_library(${PROJECT_NAME}
@@ -164,122 +140,96 @@ if(BUILD_TESTING)
find_package(rmw_implementation_cmake REQUIRED)
include(cmake/rclcpp_add_build_failure_test.cmake)
ament_add_gtest(test_client test/test_client.cpp)
if(TARGET test_client)
ament_target_dependencies(test_client
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
target_include_directories(test_client PUBLIC
${rcl_interfaces_INCLUDE_DIRS}
${rmw_INCLUDE_DIRS}
${rosidl_generator_cpp_INCLUDE_DIRS}
${rosidl_typesupport_cpp_INCLUDE_DIRS}
)
target_link_libraries(test_client ${PROJECT_NAME})
endif()
ament_add_gtest(test_expand_topic_or_service_name test/test_expand_topic_or_service_name.cpp)
if(TARGET test_expand_topic_or_service_name)
ament_target_dependencies(test_expand_topic_or_service_name
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
target_include_directories(test_expand_topic_or_service_name PUBLIC
${rcl_interfaces_INCLUDE_DIRS}
${rmw_INCLUDE_DIRS}
${rosidl_generator_cpp_INCLUDE_DIRS}
${rosidl_typesupport_cpp_INCLUDE_DIRS}
)
target_link_libraries(test_expand_topic_or_service_name ${PROJECT_NAME})
endif()
ament_add_gtest(test_function_traits test/test_function_traits.cpp)
if(TARGET test_function_traits)
ament_target_dependencies(test_function_traits
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
target_include_directories(test_function_traits PUBLIC
${rcl_interfaces_INCLUDE_DIRS}
${rmw_INCLUDE_DIRS}
${rosidl_generator_cpp_INCLUDE_DIRS}
${rosidl_typesupport_cpp_INCLUDE_DIRS}
)
endif()
ament_add_gtest(test_mapped_ring_buffer test/test_mapped_ring_buffer.cpp)
if(TARGET test_mapped_ring_buffer)
ament_target_dependencies(test_mapped_ring_buffer
"rcl"
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
target_include_directories(test_mapped_ring_buffer PUBLIC
${rcl_INCLUDE_DIRS}
${rcl_interfaces_INCLUDE_DIRS}
${rmw_INCLUDE_DIRS}
${rosidl_generator_cpp_INCLUDE_DIRS}
${rosidl_typesupport_cpp_INCLUDE_DIRS}
)
endif()
ament_add_gtest(test_intra_process_manager test/test_intra_process_manager.cpp)
if(TARGET test_intra_process_manager)
ament_target_dependencies(test_intra_process_manager
"rcl"
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
target_include_directories(test_intra_process_manager PUBLIC
${rcl_INCLUDE_DIRS}
${rcl_interfaces_INCLUDE_DIRS}
${rmw_INCLUDE_DIRS}
${rosidl_generator_cpp_INCLUDE_DIRS}
${rosidl_typesupport_cpp_INCLUDE_DIRS}
)
endif()
ament_add_gtest(test_node test/test_node.cpp)
if(TARGET test_node)
ament_target_dependencies(test_node
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
target_include_directories(test_node PUBLIC
${rcl_interfaces_INCLUDE_DIRS}
${rmw_INCLUDE_DIRS}
${rosidl_generator_cpp_INCLUDE_DIRS}
${rosidl_typesupport_cpp_INCLUDE_DIRS}
)
target_link_libraries(test_node ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_interfaces__get_node_interfaces
test/node_interfaces/test_get_node_interfaces.cpp)
if(TARGET test_node_interfaces__get_node_interfaces)
target_link_libraries(test_node_interfaces__get_node_interfaces ${PROJECT_NAME})
endif()
# TODO(wjwwood): reenable these build failure tests when I can get Jenkins to ignore their output
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ref_rclcpp_node
# test/node_interfaces/test_does_not_compile/get_node_topics_interface_const_ref_rclcpp_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ref_rclcpp_node
# ${PROJECT_NAME})
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ptr_rclcpp_node
# test/node_interfaces/test_does_not_compile/get_node_topics_interface_const_ptr_rclcpp_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ptr_rclcpp_node
# ${PROJECT_NAME})
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ref_wrapped_node
# test/node_interfaces/test_does_not_compile/get_node_topics_interface_const_ref_wrapped_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ref_rclcpp_node
# ${PROJECT_NAME})
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ptr_wrapped_node
# test/node_interfaces/test_does_not_compile/get_node_topics_interface_const_ptr_wrapped_node.cpp)
# target_link_libraries(build_failure__get_node_topics_interface_const_ptr_rclcpp_node
# ${PROJECT_NAME})
ament_add_gtest(test_node_global_args test/test_node_global_args.cpp)
if(TARGET test_node_global_args)
ament_target_dependencies(test_node_global_args
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
target_include_directories(test_node_global_args PUBLIC
${rcl_interfaces_INCLUDE_DIRS}
${rmw_INCLUDE_DIRS}
${rosidl_generator_cpp_INCLUDE_DIRS}
${rosidl_typesupport_cpp_INCLUDE_DIRS}
)
target_link_libraries(test_node_global_args ${PROJECT_NAME})
endif()
ament_add_gtest(test_node_initial_parameters test/test_node_initial_parameters.cpp)
if(TARGET test_node_initial_parameters)
target_link_libraries(test_node_initial_parameters ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_events_filter test/test_parameter_events_filter.cpp)
if(TARGET test_parameter_events_filter)
ament_target_dependencies(test_parameter_events_filter
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
target_include_directories(test_parameter_events_filter PUBLIC
${rcl_interfaces_INCLUDE_DIRS}
${rmw_INCLUDE_DIRS}
${rosidl_generator_cpp_INCLUDE_DIRS}
${rosidl_typesupport_cpp_INCLUDE_DIRS}
)
target_link_libraries(test_parameter_events_filter ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter test/test_parameter.cpp)
if(TARGET test_parameter)
ament_target_dependencies(test_parameter
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
target_include_directories(test_parameter PUBLIC
${rcl_interfaces_INCLUDE_DIRS}
${rmw_INCLUDE_DIRS}
${rosidl_generator_cpp_INCLUDE_DIRS}
${rosidl_typesupport_cpp_INCLUDE_DIRS}
)
target_link_libraries(test_parameter ${PROJECT_NAME})
endif()
@@ -289,31 +239,21 @@ if(BUILD_TESTING)
endif()
ament_add_gtest(test_publisher test/test_publisher.cpp)
if(TARGET test_publisher)
ament_target_dependencies(test_publisher
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
target_include_directories(test_publisher PUBLIC
${rcl_interfaces_INCLUDE_DIRS}
${rmw_INCLUDE_DIRS}
${rosidl_generator_cpp_INCLUDE_DIRS}
${rosidl_typesupport_cpp_INCLUDE_DIRS}
)
target_link_libraries(test_publisher ${PROJECT_NAME})
endif()
ament_add_gtest(test_publisher_subscription_count_api test/test_publisher_subscription_count_api.cpp)
if(TARGET test_publisher_subscription_count_api)
ament_target_dependencies(test_publisher_subscription_count_api
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_publisher_subscription_count_api ${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_generator_cpp"
"rosidl_typesupport_cpp"
target_include_directories(test_rate PUBLIC
${rcl_interfaces_INCLUDE_DIRS}
${rmw_INCLUDE_DIRS}
${rosidl_generator_cpp_INCLUDE_DIRS}
${rosidl_typesupport_cpp_INCLUDE_DIRS}
)
target_link_libraries(test_rate
${PROJECT_NAME}
@@ -321,55 +261,48 @@ if(BUILD_TESTING)
endif()
ament_add_gtest(test_serialized_message_allocator test/test_serialized_message_allocator.cpp)
if(TARGET test_serialized_message_allocator)
ament_target_dependencies(test_serialized_message_allocator
test_msgs
target_include_directories(test_serialized_message_allocator PUBLIC
${test_msgs_INCLUDE_DIRS}
)
target_link_libraries(test_serialized_message_allocator
${PROJECT_NAME}
${test_msgs_LIBRARIES}
)
endif()
ament_add_gtest(test_service test/test_service.cpp)
if(TARGET test_service)
ament_target_dependencies(test_service
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
target_include_directories(test_service PUBLIC
${rcl_interfaces_INCLUDE_DIRS}
${rmw_INCLUDE_DIRS}
${rosidl_generator_cpp_INCLUDE_DIRS}
${rosidl_typesupport_cpp_INCLUDE_DIRS}
)
target_link_libraries(test_service ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription test/test_subscription.cpp)
if(TARGET test_subscription)
ament_target_dependencies(test_subscription
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
target_include_directories(test_subscription PUBLIC
${rcl_interfaces_INCLUDE_DIRS}
${rmw_INCLUDE_DIRS}
${rosidl_generator_cpp_INCLUDE_DIRS}
${rosidl_typesupport_cpp_INCLUDE_DIRS}
)
target_link_libraries(test_subscription ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_publisher_count_api test/test_subscription_publisher_count_api.cpp)
if(TARGET test_subscription_publisher_count_api)
ament_target_dependencies(test_subscription_publisher_count_api
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_subscription_publisher_count_api ${PROJECT_NAME})
endif()
find_package(test_msgs REQUIRED)
ament_add_gtest(test_subscription_traits test/test_subscription_traits.cpp)
if(TARGET test_subscription_traits)
ament_target_dependencies(test_subscription_traits
"rcl"
"test_msgs"
target_include_directories(test_subscription_traits PUBLIC
${rcl_INCLUDE_DIRS}
)
ament_target_dependencies(test_subscription_traits
"test_msgs"
)
endif()
ament_add_gtest(test_find_weak_nodes test/test_find_weak_nodes.cpp)
if(TARGET test_find_weak_nodes)
ament_target_dependencies(test_find_weak_nodes
"rcl"
target_include_directories(test_find_weak_nodes PUBLIC
${rcl_INCLUDE_DIRS}
)
target_link_libraries(test_find_weak_nodes ${PROJECT_NAME})
endif()
@@ -393,8 +326,8 @@ if(BUILD_TESTING)
ament_add_gtest(test_externally_defined_services test/test_externally_defined_services.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_externally_defined_services)
ament_target_dependencies(test_externally_defined_services
"rcl"
target_include_directories(test_externally_defined_services PUBLIC
${rcl_INCLUDE_DIRS}
)
target_link_libraries(test_externally_defined_services ${PROJECT_NAME})
foreach(typesupport_impl_cpp ${typesupport_impls_cpp})
@@ -437,14 +370,6 @@ if(BUILD_TESTING)
target_link_libraries(test_time ${PROJECT_NAME})
endif()
ament_add_gtest(test_timer test/test_timer.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_timer)
ament_target_dependencies(test_timer
"rcl")
target_link_libraries(test_timer ${PROJECT_NAME})
endif()
ament_add_gtest(test_time_source test/test_time_source.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_time_source)
@@ -469,14 +394,6 @@ if(BUILD_TESTING)
target_link_libraries(test_init ${PROJECT_NAME})
endif()
ament_add_gtest(test_interface_traits test/test_interface_traits.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_interface_traits)
ament_target_dependencies(test_interface_traits
"rcl")
target_link_libraries(test_interface_traits ${PROJECT_NAME})
endif()
ament_add_gtest(test_multi_threaded_executor test/executors/test_multi_threaded_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_multi_threaded_executor)
@@ -487,17 +404,24 @@ if(BUILD_TESTING)
ament_add_gtest(test_local_parameters test/test_local_parameters.cpp)
if(TARGET test_local_parameters)
ament_target_dependencies(test_local_parameters
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
target_include_directories(test_local_parameters PUBLIC
${rcl_interfaces_INCLUDE_DIRS}
${rmw_INCLUDE_DIRS}
${rosidl_generator_cpp_INCLUDE_DIRS}
${rosidl_typesupport_cpp_INCLUDE_DIRS}
)
target_link_libraries(test_local_parameters ${PROJECT_NAME})
endif()
endif()
ament_package()
ament_package(
CONFIG_EXTRAS rclcpp-extras.cmake
)
install(
DIRECTORY cmake
DESTINATION share/${PROJECT_NAME}
)
install(
DIRECTORY include/ ${CMAKE_CURRENT_BINARY_DIR}/include/

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.
#
# Register a test which tries to compile a file and expects it to fail to build.
#
# This will create two targets, one by the given target name and a test target
# which has the same name prefixed with `test_`.
# For example, if target is `should_not_compile__use_const_argument` then there
# will be an executable target called `should_not_compile__use_const_argument`
# and a test target called `test_should_not_compile__use_const_argument`.
#
# :param target: the name of the target to be created
# :type target: string
# :param ARGN: the list of source files to be used to create the test executable
# :type ARGN: list of strings
#
macro(rclcpp_add_build_failure_test target)
if(${ARGC} EQUAL 0)
message(
FATAL_ERROR
"rclcpp_add_build_failure_test() requires a target name and "
"at least one source file")
endif()
add_executable(${target} ${ARGN})
set_target_properties(${target}
PROPERTIES
EXCLUDE_FROM_ALL TRUE
EXCLUDE_FROM_DEFAULT_BUILD TRUE)
add_test(
NAME test_${target}
COMMAND
${CMAKE_COMMAND}
--build .
--target ${target}
--config $<CONFIGURATION>
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_tests_properties(test_${target}
PROPERTIES
WILL_FAIL TRUE
LABELS "build_failure"
)
endmacro()

View File

@@ -0,0 +1,26 @@
# Copyright 2015 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set(rclcpp_node_main_SRC "${rclcpp_DIR}/../../../src/rclcpp/node_main.cpp")
function(rclcpp_create_node_main node_library_target)
if(NOT TARGET ${node_library_target})
message(FATAL_ERROR "rclcpp_create_node_main() the first argument must be a valid target name")
endif()
set(executable_name_ ${node_library_target}_node)
add_executable(${executable_name_} ${rclcpp_node_main_SRC})
target_link_libraries(${executable_name_} ${node_library_target})
install(TARGETS ${executable_name_} DESTINATION bin)
endfunction()

View File

@@ -1,4 +1,4 @@
# Copyright 2019 Open Source Robotics Foundation, Inc.
# 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.
@@ -14,5 +14,4 @@
# register node plugins
ament_index_register_resource(
"rclcpp_components" CONTENT "${_RCLCPP_COMPONENTS__NODES}")
"node_plugin" CONTENT "${_RCLCPP__NODE_PLUGINS}")

View File

@@ -1,4 +1,4 @@
# Copyright 2019 Open Source Robotics Foundation, Inc.
# 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.
@@ -13,38 +13,38 @@
# limitations under the License.
#
# Register an rclcpp component with the ament resource index.
# Register a node plugin with the ament resource index.
#
# The passed library can contain multiple nodes each registered via macro.
# The passed library can contain multiple plugins extending the node interface.
#
# :param target: the shared library target
# :type target: string
# :param ARGN: the unique plugin names being exported using class_loader
# :type ARGN: list of strings
#
macro(rclcpp_components_register_nodes target)
macro(rclcpp_register_node_plugins target)
if(NOT TARGET ${target})
message(
FATAL_ERROR
"rclcpp_components_register_nodes() first argument "
"rclcpp_register_node_plugins() first argument "
"'${target}' is not a target")
endif()
get_target_property(_target_type ${target} TYPE)
if(NOT _target_type STREQUAL "SHARED_LIBRARY")
message(
FATAL_ERROR
"rclcpp_components_register_nodes() first argument "
"rclcpp_register_node_plugins() first argument "
"'${target}' is not a shared library target")
endif()
if(${ARGC} GREATER 0)
_rclcpp_components_register_package_hook()
_rclcpp_register_package_hook()
set(_unique_names)
foreach(_arg ${ARGN})
if(_arg IN_LIST _unique_names)
message(
FATAL_ERROR
"rclcpp_components_register_nodes() the plugin names "
"rclcpp_register_node_plugins() the plugin names "
"must be unique (multiple '${_arg}')")
endif()
list(APPEND _unique_names "${_arg}")
@@ -54,9 +54,8 @@ macro(rclcpp_components_register_nodes target)
else()
set(_path "lib")
endif()
set(_RCLCPP_COMPONENTS__NODES
"${_RCLCPP_COMPONENTS__NODES}${_arg};${_path}/$<TARGET_FILE_NAME:${target}>\n")
set(_RCLCPP__NODE_PLUGINS
"${_RCLCPP__NODE_PLUGINS}${_arg};${_path}/$<TARGET_FILE_NAME:${target}>\n")
endforeach()
endif()
endmacro()

View File

@@ -65,8 +65,7 @@ void * retyped_reallocate(void * untyped_pointer, size_t size, void * untyped_al
// Convert a std::allocator_traits-formatted Allocator into an rcl allocator
template<
typename T,
typename Alloc,
typename T, typename Alloc,
typename std::enable_if<!std::is_same<Alloc, std::allocator<void>>::value>::type * = nullptr>
rcl_allocator_t get_rcl_allocator(Alloc & allocator)
{
@@ -84,8 +83,7 @@ rcl_allocator_t get_rcl_allocator(Alloc & allocator)
// TODO(jacquelinekay) Workaround for an incomplete implementation of std::allocator<void>
template<
typename T,
typename Alloc,
typename T, typename Alloc,
typename std::enable_if<std::is_same<Alloc, std::allocator<void>>::value>::type * = nullptr>
rcl_allocator_t get_rcl_allocator(Alloc & allocator)
{

View File

@@ -36,7 +36,6 @@ class AnySubscriptionCallback
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
using MessageAlloc = typename MessageAllocTraits::allocator_type;
using MessageDeleter = allocator::Deleter<MessageAlloc, MessageT>;
using ConstMessageSharedPtr = std::shared_ptr<const MessageT>;
using MessageUniquePtr = std::unique_ptr<MessageT, MessageDeleter>;
using SharedPtrCallback = std::function<void (const std::shared_ptr<MessageT>)>;
@@ -155,6 +154,7 @@ public:
void dispatch(
std::shared_ptr<MessageT> message, const rmw_message_info_t & message_info)
{
(void)message_info;
if (shared_ptr_callback_) {
shared_ptr_callback_(message);
} else if (shared_ptr_with_info_callback_) {
@@ -177,50 +177,30 @@ public:
}
void dispatch_intra_process(
ConstMessageSharedPtr message, const rmw_message_info_t & message_info)
{
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_)
{
throw std::runtime_error("unexpected dispatch_intra_process const shared "
"message call with no const shared_ptr callback");
} else {
throw std::runtime_error("unexpected message without any callback set");
}
}
}
void dispatch_intra_process(
MessageUniquePtr message, const rmw_message_info_t & message_info)
MessageUniquePtr & message, const rmw_message_info_t & message_info)
{
(void)message_info;
if (shared_ptr_callback_) {
typename std::shared_ptr<MessageT> shared_message = std::move(message);
shared_ptr_callback_(shared_message);
} else if (shared_ptr_with_info_callback_) {
typename std::shared_ptr<MessageT> shared_message = std::move(message);
shared_ptr_with_info_callback_(shared_message, message_info);
} else if (const_shared_ptr_callback_) {
typename std::shared_ptr<MessageT const> const_shared_message = std::move(message);
const_shared_ptr_callback_(const_shared_message);
} else if (const_shared_ptr_with_info_callback_) {
typename std::shared_ptr<MessageT const> const_shared_message = std::move(message);
const_shared_ptr_with_info_callback_(const_shared_message, message_info);
} else if (unique_ptr_callback_) {
unique_ptr_callback_(std::move(message));
} else if (unique_ptr_with_info_callback_) {
unique_ptr_with_info_callback_(std::move(message), message_info);
} else if (const_shared_ptr_callback_ || const_shared_ptr_with_info_callback_) {
throw std::runtime_error("unexpected dispatch_intra_process unique message call"
" with const shared_ptr callback");
} else {
throw std::runtime_error("unexpected message without any callback set");
}
}
bool use_take_shared_method()
{
return const_shared_ptr_callback_ || const_shared_ptr_with_info_callback_;
}
private:
std::shared_ptr<MessageAlloc> message_allocator_;
MessageDeleter message_deleter_;

View File

@@ -21,7 +21,6 @@
#include <vector>
#include "rclcpp/client.hpp"
#include "rclcpp/publisher.hpp"
#include "rclcpp/service.hpp"
#include "rclcpp/subscription.hpp"
#include "rclcpp/timer.hpp"
@@ -93,10 +92,6 @@ public:
protected:
RCLCPP_DISABLE_COPY(CallbackGroup)
RCLCPP_PUBLIC
void
add_publisher(const rclcpp::PublisherBase::SharedPtr publisher_ptr);
RCLCPP_PUBLIC
void
add_subscription(const rclcpp::SubscriptionBase::SharedPtr subscription_ptr);

View File

@@ -78,10 +78,10 @@ public:
bool
service_is_ready() const;
template<typename RepT = int64_t, typename RatioT = std::milli>
template<typename RatioT = std::milli>
bool
wait_for_service(
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
std::chrono::duration<int64_t, RatioT> timeout = std::chrono::duration<int64_t, RatioT>(-1))
{
return wait_for_service_nanoseconds(
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)

View File

@@ -16,6 +16,9 @@
#define RCLCPP__CLOCK_HPP_
#include <functional>
#include <memory>
#include <mutex>
#include <vector>
#include "rclcpp/macros.hpp"
#include "rclcpp/time.hpp"
@@ -32,17 +35,13 @@ 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 &)>;
JumpHandler(
pre_callback_t pre_callback,
post_callback_t post_callback,
std::function<void()> pre_callback,
std::function<void(const rcl_time_jump_t &)> post_callback,
const rcl_jump_threshold_t & threshold);
pre_callback_t pre_callback;
post_callback_t post_callback;
std::function<void()> pre_callback;
std::function<void(const rcl_time_jump_t &)> post_callback;
rcl_jump_threshold_t notice_threshold;
};
@@ -51,74 +50,38 @@ class Clock
public:
RCLCPP_SMART_PTR_DEFINITIONS(Clock)
/// Default c'tor
/**
* Initializes the clock instance with the given clock_type.
*
* \param clock_type type of the clock.
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
*/
RCLCPP_PUBLIC
explicit Clock(rcl_clock_type_t clock_type = RCL_SYSTEM_TIME);
RCLCPP_PUBLIC
~Clock();
/**
* Returns current time from the time source specified by clock_type.
*
* \return current time.
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
*/
RCLCPP_PUBLIC
Time
now();
/**
* Returns the clock of the type `RCL_ROS_TIME` is active.
*
* \return true if the clock is active
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw if
* the current clock does not have the clock_type `RCL_ROS_TIME`.
*/
RCLCPP_PUBLIC
bool
ros_time_is_active();
RCLCPP_PUBLIC
rcl_clock_t *
get_clock_handle() noexcept;
get_clock_handle();
RCLCPP_PUBLIC
rcl_clock_type_t
get_clock_type() const noexcept;
get_clock_type();
// Add a callback to invoke if the jump threshold is exceeded.
/**
* These callback functions must remain valid as long as the
* returned shared pointer is valid.
*
* Function will register callbacks to the callback queue. On time jump all
* callbacks will be executed whose threshold is greater then the time jump;
* The logic will first call selected pre_callbacks and then all selected
* post_callbacks.
*
* Function is only applicable if the clock_type is `RCL_ROS_TIME`
*
* \param pre_callback. Must be non-throwing
* \param post_callback. Must be non-throwing.
* \param threshold. Callbacks will be triggered if the time jump is greater
* then the threshold.
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
* \throws std::bad_alloc if the allocation of the JumpHandler fails.
* \warning the instance of the clock must remain valid as long as any created
* JumpHandler.
*/
RCLCPP_PUBLIC
JumpHandler::SharedPtr
create_jump_callback(
JumpHandler::pre_callback_t pre_callback,
JumpHandler::post_callback_t post_callback,
std::function<void()> pre_callback,
std::function<void(const rcl_time_jump_t &)> post_callback,
const rcl_jump_threshold_t & threshold);
private:

View File

@@ -18,30 +18,19 @@
#include <memory>
#include <string>
#include "rclcpp/node_interfaces/get_node_topics_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/node_options.hpp"
#include "rclcpp/publisher_factory.hpp"
#include "rclcpp/publisher_options.hpp"
#include "rclcpp/qos.hpp"
#include "rmw/qos_profiles.h"
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")]]
template<typename MessageT, typename AllocatorT, typename PublisherT>
std::shared_ptr<PublisherT>
create_publisher(
rclcpp::node_interfaces::NodeTopicsInterface * node_topics,
const std::string & topic_name,
const rmw_qos_profile_t & qos_profile,
const PublisherEventCallbacks & event_callbacks,
rclcpp::callback_group::CallbackGroup::SharedPtr group,
bool use_intra_process_comms,
std::shared_ptr<AllocatorT> allocator)
{
@@ -50,69 +39,10 @@ create_publisher(
auto pub = node_topics->create_publisher(
topic_name,
rclcpp::create_publisher_factory<MessageT, AllocatorT, PublisherT>(event_callbacks, allocator),
rclcpp::create_publisher_factory<MessageT, AllocatorT, PublisherT>(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<
typename MessageT,
typename AllocatorT = std::allocator<void>,
typename PublisherT = ::rclcpp::Publisher<MessageT, AllocatorT>,
typename NodeT>
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>()
))
{
using rclcpp::node_interfaces::get_node_topics_interface;
auto node_topics = get_node_topics_interface(node);
std::shared_ptr<AllocatorT> allocator = options.allocator;
if (!allocator) {
allocator = std::make_shared<AllocatorT>();
}
bool use_intra_process;
switch (options.use_intra_process_comm) {
case IntraProcessSetting::Enable:
use_intra_process = true;
break;
case IntraProcessSetting::Disable:
use_intra_process = false;
break;
case IntraProcessSetting::NodeDefault:
use_intra_process = node_topics->get_node_base_interface()->get_use_intra_process_default();
break;
default:
throw std::runtime_error("Unrecognized IntraProcessSetting value");
break;
}
// TODO(wjwwood): convert all of the interfaces to use QoS and PublisherOptionsBase
auto pub = node_topics->create_publisher(
topic_name,
rclcpp::create_publisher_factory<MessageT, AllocatorT, PublisherT>(
options.event_callbacks,
allocator
),
options.template to_rcl_publisher_options<MessageT>(qos),
use_intra_process
);
node_topics->add_publisher(pub, options.callback_group);
node_topics->add_publisher(pub);
return std::dynamic_pointer_cast<PublisherT>(pub);
}

View File

@@ -19,11 +19,8 @@
#include <string>
#include <utility>
#include "rclcpp/node_interfaces/get_node_topics_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/subscription_factory.hpp"
#include "rclcpp/subscription_options.hpp"
#include "rclcpp/qos.hpp"
#include "rmw/qos_profiles.h"
namespace rclcpp
@@ -35,15 +32,12 @@ template<
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,
@@ -58,10 +52,7 @@ create_subscription(
auto factory = rclcpp::create_subscription_factory
<MessageT, CallbackT, AllocatorT, CallbackMessageT, SubscriptionT>(
std::forward<CallbackT>(callback),
event_callbacks,
msg_mem_strat,
allocator);
std::forward<CallbackT>(callback), msg_mem_strat, allocator);
auto sub = node_topics->create_subscription(
topic_name,
@@ -72,75 +63,6 @@ create_subscription(
return std::dynamic_pointer_cast<SubscriptionT>(sub);
}
/// Create and return a subscription of the given MessageT type.
/**
* The NodeT type only needs to have a method called get_node_topics_interface()
* which returns a shared_ptr to a NodeTopicsInterface, or be a
* NodeTopicsInterface pointer itself.
*/
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 NodeT>
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 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));
if (!msg_mem_strat) {
using rclcpp::message_memory_strategy::MessageMemoryStrategy;
msg_mem_strat = MessageMemoryStrategy<CallbackMessageT, AllocatorT>::create_default();
}
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);
}
} // namespace rclcpp
#endif // RCLCPP__CREATE_SUBSCRIPTION_HPP_

View File

@@ -23,87 +23,91 @@
namespace rclcpp
{
class RCLCPP_PUBLIC Duration
class Duration
{
public:
RCLCPP_PUBLIC
Duration(int32_t seconds, uint32_t nanoseconds);
explicit Duration(rcl_duration_value_t nanoseconds);
RCLCPP_PUBLIC
explicit Duration(
rcl_duration_value_t nanoseconds);
explicit Duration(std::chrono::nanoseconds nanoseconds);
RCLCPP_PUBLIC
explicit Duration(
std::chrono::nanoseconds nanoseconds);
// intentionally not using explicit to create a conversion constructor
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)
RCLCPP_PUBLIC
Duration(
const builtin_interfaces::msg::Duration & duration_msg);
RCLCPP_PUBLIC
explicit Duration(const rcl_duration_t & duration);
RCLCPP_PUBLIC
Duration(const Duration & rhs);
virtual ~Duration() = default;
RCLCPP_PUBLIC
virtual ~Duration();
RCLCPP_PUBLIC
operator builtin_interfaces::msg::Duration() const;
// cppcheck-suppress operatorEq // this is a false positive from cppcheck
RCLCPP_PUBLIC
Duration &
operator=(const Duration & rhs);
RCLCPP_PUBLIC
Duration &
operator=(const builtin_interfaces::msg::Duration & Duration_msg);
RCLCPP_PUBLIC
bool
operator==(const rclcpp::Duration & rhs) const;
RCLCPP_PUBLIC
bool
operator<(const rclcpp::Duration & rhs) const;
RCLCPP_PUBLIC
bool
operator<=(const rclcpp::Duration & rhs) const;
RCLCPP_PUBLIC
bool
operator>=(const rclcpp::Duration & rhs) const;
RCLCPP_PUBLIC
bool
operator>(const rclcpp::Duration & rhs) const;
RCLCPP_PUBLIC
Duration
operator+(const rclcpp::Duration & rhs) const;
RCLCPP_PUBLIC
Duration
operator-(const rclcpp::Duration & rhs) const;
static
Duration
RCLCPP_PUBLIC
static Duration
max();
RCLCPP_PUBLIC
Duration
operator*(double scale) const;
RCLCPP_PUBLIC
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.
RCLCPP_PUBLIC
double
seconds() 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;
private:
rcl_duration_t rcl_duration_;
};

View File

@@ -110,15 +110,13 @@ public:
* \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]] (
throw_from_rcl_error(
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
{
@@ -187,35 +185,14 @@ public:
class InvalidParametersException : public std::runtime_error
{
public:
// Inherit constructors from runtime_error.
// Inherit constructors from runtime_error;
using std::runtime_error::runtime_error;
};
/// Thrown if passed parameter value is invalid.
/// Throwing 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.
// Inherit constructors from runtime_error;
using std::runtime_error::runtime_error;
};

View File

@@ -151,11 +151,11 @@ public:
* 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>
template<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))
std::chrono::duration<int64_t, T> timeout = std::chrono::duration<int64_t, T>(-1))
{
return spin_node_once_nanoseconds(
node,
@@ -164,11 +164,11 @@ public:
}
/// Convenience function which takes Node and forwards NodeBaseInterface.
template<typename NodeT = rclcpp::Node, typename RepT = int64_t, typename T = std::milli>
template<typename NodeT = rclcpp::Node, 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))
std::chrono::duration<int64_t, T> timeout = std::chrono::duration<int64_t, T>(-1))
{
return spin_node_once_nanoseconds(
node->get_node_base_interface(),
@@ -218,11 +218,11 @@ public:
* code.
* \return The return code, one of `SUCCESS`, `INTERRUPTED`, or `TIMEOUT`.
*/
template<typename ResponseT, typename TimeRepT = int64_t, typename TimeT = std::milli>
template<typename ResponseT, 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))
std::chrono::duration<int64_t, TimeT> timeout = std::chrono::duration<int64_t, TimeT>(-1))
{
// TODO(wjwwood): does not work recursively; can't call spin_node_until_future_complete
// inside a callback executed by an executor.

View File

@@ -65,13 +65,13 @@ 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>
template<typename ResponseT, typename TimeT = std::milli>
rclcpp::executor::FutureReturnCode
spin_node_until_future_complete(
rclcpp::executor::Executor & executor,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
std::shared_future<ResponseT> & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
std::chrono::duration<int64_t, TimeT> timeout = std::chrono::duration<int64_t, TimeT>(-1))
{
// TODO(wjwwood): does not work recursively; can't call spin_node_until_future_complete
// inside a callback executed by an executor.
@@ -81,14 +81,13 @@ spin_node_until_future_complete(
return retcode;
}
template<typename NodeT = rclcpp::Node, typename ResponseT, typename TimeRepT = int64_t,
typename TimeT = std::milli>
template<typename NodeT = rclcpp::Node, typename ResponseT, typename TimeT = std::milli>
rclcpp::executor::FutureReturnCode
spin_node_until_future_complete(
rclcpp::executor::Executor & executor,
std::shared_ptr<NodeT> node_ptr,
std::shared_future<ResponseT> & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
std::chrono::duration<int64_t, TimeT> timeout = std::chrono::duration<int64_t, TimeT>(-1))
{
return rclcpp::executors::spin_node_until_future_complete(
executor,
@@ -99,24 +98,23 @@ spin_node_until_future_complete(
} // namespace executors
template<typename FutureT, typename TimeRepT = int64_t, typename TimeT = std::milli>
template<typename FutureT, typename TimeT = std::milli>
rclcpp::executor::FutureReturnCode
spin_until_future_complete(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
std::shared_future<FutureT> & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
std::chrono::duration<int64_t, TimeT> timeout = std::chrono::duration<int64_t, TimeT>(-1))
{
rclcpp::executors::SingleThreadedExecutor executor;
return executors::spin_node_until_future_complete<FutureT>(executor, node_ptr, future, timeout);
}
template<typename NodeT = rclcpp::Node, typename FutureT, typename TimeRepT = int64_t,
typename TimeT = std::milli>
template<typename NodeT = rclcpp::Node, typename FutureT, typename TimeT = std::milli>
rclcpp::executor::FutureReturnCode
spin_until_future_complete(
std::shared_ptr<NodeT> node_ptr,
std::shared_future<FutureT> & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
std::chrono::duration<int64_t, TimeT> timeout = std::chrono::duration<int64_t, TimeT>(-1))
{
return rclcpp::spin_until_future_complete(node_ptr->get_node_base_interface(), future, timeout);
}

View File

@@ -78,6 +78,7 @@ private:
size_t number_of_threads_;
bool yield_before_execute_;
std::mutex scheduled_timers_mutex_;
std::set<TimerBase::SharedPtr> scheduled_timers_;
};

View File

@@ -25,15 +25,14 @@
#include <memory>
#include <mutex>
#include <unordered_map>
#include <utility>
#include <set>
#include "rclcpp/allocator/allocator_deleter.hpp"
#include "rclcpp/intra_process_manager_impl.hpp"
#include "rclcpp/mapped_ring_buffer.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/publisher_base.hpp"
#include "rclcpp/subscription_base.hpp"
#include "rclcpp/publisher.hpp"
#include "rclcpp/subscription.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
@@ -185,11 +184,21 @@ public:
* \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
template<typename MessageT, typename Alloc>
uint64_t
add_publisher(
rclcpp::PublisherBase::SharedPtr publisher,
size_t buffer_size = 0);
typename Publisher<MessageT, Alloc>::SharedPtr publisher,
size_t buffer_size = 0)
{
auto id = IntraProcessManager::get_next_unique_id();
size_t size = buffer_size > 0 ? buffer_size : publisher->get_queue_size();
auto mrb = mapped_ring_buffer::MappedRingBuffer<
MessageT,
typename Publisher<MessageT, Alloc>::MessageAlloc
>::make_shared(size, publisher->get_allocator());
impl_->add_publisher(id, publisher, mrb, size);
return id;
}
/// Unregister a publisher using the publisher's unique id.
/**
@@ -233,11 +242,12 @@ public:
* \return the message sequence number.
*/
template<
typename MessageT, typename Alloc = std::allocator<void>>
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::shared_ptr<const MessageT> message)
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>;
@@ -260,35 +270,6 @@ public:
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
@@ -353,45 +334,10 @@ public:
// 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);
typed_buffer->get_copy_at_key(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);
typed_buffer->pop_at_key(message_sequence_number, message);
}
}
@@ -400,11 +346,6 @@ 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

View File

@@ -16,7 +16,6 @@
#define RCLCPP__INTRA_PROCESS_MANAGER_IMPL_HPP_
#include <algorithm>
#include <array>
#include <atomic>
#include <cstring>
#include <functional>
@@ -25,17 +24,14 @@
#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/publisher.hpp"
#include "rclcpp/subscription.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
@@ -84,9 +80,6 @@ public:
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)
};
@@ -102,7 +95,9 @@ public:
add_subscription(uint64_t id, SubscriptionBase::SharedPtr subscription)
{
subscriptions_[id] = subscription;
subscription_ids_by_topic_[fixed_size_string(subscription->get_topic_name())].insert(id);
// subscription->get_topic_name() -> const char * can be used as the key,
// since subscriptions_ shares the ownership of subscription
subscription_ids_by_topic_[subscription->get_topic_name()].insert(id);
}
void
@@ -177,8 +172,7 @@ public:
}
// Figure out what subscriptions should receive the message.
auto & destined_subscriptions =
subscription_ids_by_topic_[fixed_size_string(publisher->get_topic_name())];
auto & destined_subscriptions = subscription_ids_by_topic_[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(
@@ -254,52 +248,9 @@ public:
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>;
@@ -311,11 +262,19 @@ private:
std::hash<uint64_t>, std::equal_to<uint64_t>,
RebindAlloc<std::pair<const uint64_t, SubscriptionBase::WeakPtr>>>;
struct strcmp_wrapper
{
bool
operator()(const char * lhs, const char * rhs) const
{
return std::strcmp(lhs, rhs) < 0;
}
};
using IDTopicMap = std::map<
FixedSizeString,
const char *,
AllocSet,
strcmp_wrapper,
RebindAlloc<std::pair<const FixedSizeString, AllocSet>>>;
RebindAlloc<std::pair<const char * const, AllocSet>>>;
SubscriptionMap subscriptions_;

View File

@@ -1,34 +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_SETTING_HPP_
#define RCLCPP__INTRA_PROCESS_SETTING_HPP_
namespace rclcpp
{
/// Used as argument in create_publisher and create_subscriber.
enum class IntraProcessSetting
{
/// Explicitly enable intraprocess comm at publisher/subscription level.
Enable,
/// Explicitly disable intraprocess comm at publisher/subscription level.
Disable,
/// Take intraprocess configuration from the node.
NodeDefault
};
} // namespace rclcpp
#endif // RCLCPP__INTRA_PROCESS_SETTING_HPP_

View File

@@ -20,7 +20,6 @@
#include <cstdint>
#include <memory>
#include <mutex>
#include <stdexcept>
#include <utility>
#include <vector>
@@ -39,7 +38,7 @@ 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.
/// Ring buffer container of 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.
@@ -65,7 +64,6 @@ public:
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.
@@ -103,105 +101,57 @@ public:
* \param value if the key is found, the value is stored in this parameter
*/
void
get(uint64_t key, ElemUniquePtr & value)
get_copy_at_key(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.");
}
auto ptr = ElemAllocTraits::allocate(*allocator_.get(), 1);
ElemAllocTraits::construct(*allocator_.get(), ptr, *it->value);
value = ElemUniquePtr(ptr);
}
}
/// Share ownership of the value stored in the ring buffer at the given key.
/// Return ownership of the value stored in the ring buffer, leaving a copy.
/**
* The key is matched if an element in the ring buffer has a matching key.
* The key is matched if an element in the ring bufer has a matching key.
* This method will allocate in order to store a copy.
*
* The key is not guaranteed to be unique, see the class docs for more.
*
* The ownership of the currently stored object is returned, but a copy is
* made and stored in its place.
* This means that multiple calls to this function for a particular element
* will result in returning the copied and stored object not the original.
* This also means that later calls to pop_at_key will not return the
* originally stored object, since it was returned by the first call to this
* method.
*
* 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)
get_ownership_at_key(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;
// Make a copy.
auto ptr = ElemAllocTraits::allocate(*allocator_.get(), 1);
ElemAllocTraits::construct(*allocator_.get(), ptr, *it->value);
auto copy = ElemUniquePtr(ptr);
// Return the original.
value.swap(it->value);
// Store the copy.
it->value.swap(copy);
}
}
/// Give the ownership of the stored value to the caller, at the given key.
/// Return 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.
*
@@ -213,18 +163,13 @@ public:
* \param value if the key is found, the value is stored in this parameter
*/
void
pop(uint64_t key, ConstElemSharedPtr & value)
pop_at_key(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->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.");
}
value.swap(it->value);
it->in_use = false;
}
}
@@ -235,44 +180,29 @@ public:
* 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.
* After insertion, if a pair was replaced, then value will contain ownership
* of that displaced value. Otherwise it will be a nullptr.
*
* \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)
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.shared_value = value;
element.in_use = true;
elements_[head_].key = key;
elements_[head_].value.swap(value);
elements_[head_].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)
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;
ElemUniquePtr temp = std::move(value);
return push_and_replace(key, temp);
}
/// Return true if the key is found in the ring buffer, otherwise false.
@@ -286,28 +216,27 @@ public:
private:
RCLCPP_DISABLE_COPY(MappedRingBuffer<T, Alloc>)
struct Element
struct element
{
uint64_t key;
ElemUniquePtr unique_value;
ConstElemSharedPtr shared_value;
ElemUniquePtr value;
bool in_use;
};
using VectorAlloc = typename std::allocator_traits<Alloc>::template rebind_alloc<Element>;
using VectorAlloc = typename std::allocator_traits<Alloc>::template rebind_alloc<element>;
typename std::vector<Element, VectorAlloc>::iterator
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 {
[key](element & e) -> bool {
return e.key == key && e.in_use;
});
return it;
}
std::vector<Element, VectorAlloc> elements_;
std::vector<element, VectorAlloc> elements_;
size_t head_;
std::shared_ptr<ElemAlloc> allocator_;
std::mutex data_mutex_;

View File

@@ -51,7 +51,6 @@ public:
virtual size_t number_of_ready_subscriptions() const = 0;
virtual size_t number_of_ready_services() const = 0;
virtual size_t number_of_ready_clients() const = 0;
virtual size_t number_of_ready_events() const = 0;
virtual size_t number_of_ready_timers() const = 0;
virtual size_t number_of_guard_conditions() const = 0;
virtual size_t number_of_waitables() const = 0;

File diff suppressed because it is too large Load Diff

View File

@@ -36,12 +36,11 @@
#include "rcl_interfaces/msg/intra_process_message.hpp"
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/intra_process_manager.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/create_publisher.hpp"
#include "rclcpp/create_service.hpp"
#include "rclcpp/create_subscription.hpp"
#include "rclcpp/intra_process_manager.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -52,147 +51,110 @@
namespace rclcpp
{
RCLCPP_LOCAL
inline
std::string
extend_name_with_sub_namespace(const std::string & name, const std::string & sub_namespace)
template<typename MessageT, typename Alloc, typename PublisherT>
std::shared_ptr<PublisherT>
Node::create_publisher(
const std::string & topic_name, size_t qos_history_depth,
std::shared_ptr<Alloc> allocator)
{
std::string name_with_sub_namespace(name);
if (sub_namespace != "" && name.front() != '/' && name.front() != '~') {
name_with_sub_namespace = sub_namespace + "/" + name;
if (!allocator) {
allocator = std::make_shared<Alloc>();
}
return name_with_sub_namespace;
rmw_qos_profile_t qos = rmw_qos_profile_default;
qos.depth = qos_history_depth;
return this->create_publisher<MessageT, Alloc, PublisherT>(topic_name, qos, allocator);
}
template<typename MessageT, typename AllocatorT, typename PublisherT>
template<typename MessageT, typename Alloc, 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);
}
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 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);
}
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,
const std::string & topic_name, const rmw_qos_profile_t & qos_profile,
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>(
if (!allocator) {
allocator = std::make_shared<Alloc>();
}
return rclcpp::create_publisher<MessageT, Alloc, PublisherT>(
this->node_topics_.get(),
topic_name,
rclcpp::QoS(rclcpp::KeepLast(qos_history_depth)),
std::forward<CallbackT>(callback),
sub_options,
msg_mem_strat);
qos_profile,
use_intra_process_comms_,
allocator);
}
template<typename DurationRepT, typename DurationT, typename CallbackT>
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)
{
using CallbackMessageT = typename rclcpp::subscription_traits::has_message_type<CallbackT>::type;
if (!allocator) {
allocator = std::make_shared<Alloc>();
}
if (!msg_mem_strat) {
using rclcpp::message_memory_strategy::MessageMemoryStrategy;
msg_mem_strat = MessageMemoryStrategy<CallbackMessageT, Alloc>::create_default();
}
return rclcpp::create_subscription<MessageT, CallbackT, Alloc, CallbackMessageT, SubscriptionT>(
this->node_topics_.get(),
topic_name,
std::forward<CallbackT>(callback),
qos_profile,
group,
ignore_local_publications,
use_intra_process_comms_,
msg_mem_strat,
allocator);
}
template<
typename MessageT,
typename CallbackT,
typename Alloc,
typename SubscriptionT>
std::shared_ptr<SubscriptionT>
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)
{
rmw_qos_profile_t qos = rmw_qos_profile_default;
qos.depth = qos_history_depth;
return this->create_subscription<MessageT>(
topic_name,
std::forward<CallbackT>(callback),
qos,
group,
ignore_local_publications,
msg_mem_strat,
allocator);
}
template<typename DurationT, typename CallbackT>
typename rclcpp::WallTimer<CallbackT>::SharedPtr
Node::create_wall_timer(
std::chrono::duration<DurationRepT, DurationT> period,
std::chrono::duration<int64_t, DurationT> period,
CallbackT callback,
rclcpp::callback_group::CallbackGroup::SharedPtr group)
{
@@ -220,7 +182,7 @@ Node::create_client(
auto cli = Client<ServiceT>::make_shared(
node_base_.get(),
node_graph_,
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
service_name,
options);
auto cli_base_ptr = std::dynamic_pointer_cast<ClientBase>(cli);
@@ -237,176 +199,8 @@ Node::create_service(
rclcpp::callback_group::CallbackGroup::SharedPtr group)
{
return rclcpp::create_service<ServiceT, CallbackT>(
node_base_,
node_services_,
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
std::forward<CallbackT>(callback),
qos_profile,
group);
}
template<typename ParameterT>
auto
Node::declare_parameter(
const std::string & name,
const ParameterT & default_value,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor)
{
return this->declare_parameter(
name,
rclcpp::ParameterValue(default_value),
parameter_descriptor
).get<ParameterT>();
}
template<typename ParameterT>
std::vector<ParameterT>
Node::declare_parameters(
const std::string & namespace_,
const std::map<std::string, ParameterT> & parameters)
{
std::vector<ParameterT> result;
std::string normalized_namespace = namespace_.empty() ? "" : (namespace_ + ".");
std::transform(
parameters.begin(), parameters.end(), std::back_inserter(result),
[this, &normalized_namespace](auto element) {
return this->declare_parameter(normalized_namespace + element.first, element.second);
}
);
return result;
}
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)
{
std::vector<ParameterT> result;
std::string normalized_namespace = namespace_.empty() ? "" : (namespace_ + ".");
std::transform(
parameters.begin(), parameters.end(), std::back_inserter(result),
[this, &normalized_namespace](auto element) {
return static_cast<ParameterT>(
this->declare_parameter(
normalized_namespace + element.first,
element.second.first,
element.second.second)
);
}
);
return result;
}
template<typename ParameterT>
void
Node::set_parameter_if_not_set(
const std::string & name,
const ParameterT & value)
{
if (
!this->has_parameter(name) ||
this->describe_parameter(name).type == PARAMETER_NOT_SET)
{
this->set_parameter(rclcpp::Parameter(name, value));
}
}
// this is a partially-specialized version of set_parameter_if_not_set above,
// where our concrete type for ParameterT is std::map, but the to-be-determined
// type is the value in the map.
template<typename ParameterT>
void
Node::set_parameters_if_not_set(
const std::string & name,
const std::map<std::string, ParameterT> & values)
{
std::vector<rclcpp::Parameter> params;
for (const auto & val : values) {
std::string parameter_name = name + "." + val.first;
if (
!this->has_parameter(parameter_name) ||
this->describe_parameter(parameter_name).type == PARAMETER_NOT_SET)
{
params.push_back(rclcpp::Parameter(parameter_name, val.second));
}
}
this->set_parameters(params);
}
template<typename ParameterT>
bool
Node::get_parameter(const std::string & name, ParameterT & parameter) const
{
std::string sub_name = extend_name_with_sub_namespace(name, this->get_sub_namespace());
rclcpp::Parameter parameter_variant;
bool result = get_parameter(sub_name, parameter_variant);
if (result) {
parameter = static_cast<ParameterT>(parameter_variant.get_value<ParameterT>());
}
return result;
}
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());
bool got_parameter = get_parameter(sub_name, parameter);
if (!got_parameter) {
parameter = alternative_value;
}
return got_parameter;
}
// 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
{
std::map<std::string, rclcpp::Parameter> params;
bool result = node_parameters_->get_parameters_by_prefix(prefix, params);
if (result) {
for (const auto & param : params) {
values[param.first] = static_cast<ParameterT>(param.second.get_value<ParameterT>());
}
}
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;
}
node_base_, node_services_,
service_name, std::forward<CallbackT>(callback), qos_profile, group);
}
template<typename CallbackT>
@@ -416,6 +210,115 @@ Node::register_param_change_callback(CallbackT && callback)
this->node_parameters_->register_param_change_callback(std::forward<CallbackT>(callback));
}
template<typename ParameterT>
void
Node::declare_parameter(
const std::string & name,
const ParameterT & default_value,
bool read_only)
{
this->declare_parameter(name, rclcpp::ParameterValue(default_value), read_only);
}
template<typename ParameterT>
void
Node::set_parameter_if_not_set(
const std::string & name,
const ParameterT & value)
{
rclcpp::Parameter parameter;
if (!this->get_parameter(name, parameter)) {
this->set_parameters({
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 MapValueT>
void
Node::set_parameters_if_not_set(
const std::string & name,
const std::map<std::string, MapValueT> & values)
{
std::vector<rclcpp::Parameter> params;
for (const auto & val : values) {
std::string param_name = name + "." + val.first;
rclcpp::Parameter parameter;
if (!this->get_parameter(param_name, parameter)) {
params.push_back(rclcpp::Parameter(param_name, val.second));
}
}
this->set_parameters(params);
}
template<typename ParameterT>
bool
Node::get_parameter(const std::string & name, ParameterT & value) const
{
rclcpp::Parameter parameter;
bool result = get_parameter(name, parameter);
if (result) {
value = parameter.get_value<ParameterT>();
}
return result;
}
// 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 MapValueT>
bool
Node::get_parameters(
const std::string & name,
std::map<std::string, MapValueT> & values) const
{
std::map<std::string, rclcpp::Parameter> params;
bool result = node_parameters_->get_parameters_by_prefix(name, params);
if (result) {
for (const auto & param : params) {
values[param.first] = param.second.get_value<MapValueT>();
}
}
return result;
}
template<typename ParameterT>
bool
Node::get_parameter_or(
const std::string & name,
ParameterT & value,
const ParameterT & alternative_value) const
{
bool got_parameter = get_parameter(name, value);
if (!got_parameter) {
value = alternative_value;
}
return got_parameter;
}
template<typename ParameterT>
void
Node::get_parameter_or_set(
const std::string & name,
ParameterT & value,
const ParameterT & alternative_value)
{
bool got_parameter = get_parameter(name, value);
if (!got_parameter) {
this->set_parameters({
rclcpp::Parameter(name, alternative_value),
});
value = alternative_value;
}
}
} // namespace rclcpp
#endif // RCLCPP__NODE_IMPL_HPP_

View File

@@ -0,0 +1,162 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__NODE_INTERFACES__GET_NODE_PARAMETERS_INTERFACE_HPP_
#define RCLCPP__NODE_INTERFACES__GET_NODE_PARAMETERS_INTERFACE_HPP_
#include <memory>
#include <utility>
#include <type_traits>
#include "rclcpp/node_interfaces/node_parameters_interface.hpp"
/// This header provides the get_node_parameters_interface() template function.
/**
* This function is useful for getting the NodeParametersInterface pointer from
* various kinds of Node-like classes.
*
* It's able to get the NodeParametersInterface pointer so long as the class
* has a method called ``get_node_parameters_interface()`` which returns
* either a pointer (const or not) to a NodeParametersInterface or a
* std::shared_ptr to a NodeParametersInterface.
*/
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_parameters_interface() which returns various types,
// e.g. const pointer or a shared pointer.
template<typename NodeType, typename ReturnType>
struct has_get_node_parameters_interface
{
private:
template<typename T>
static constexpr
auto
check(T *)->typename std::is_same<
decltype(std::declval<T>().get_node_parameters_interface()),
ReturnType
>::type;
template<typename>
static constexpr
std::false_type
check(...);
public:
using type = decltype(check<NodeType>(nullptr));
static constexpr bool value = type::value;
};
// If NodeType is a pointer to NodeParametersInterface already (just normal function overload).
inline
const rclcpp::node_interfaces::NodeParametersInterface *
get_node_parameters_interface_from_pointer(
const rclcpp::node_interfaces::NodeParametersInterface * pointer)
{
return pointer;
}
// If NodeType has a method called get_node_parameters_interface() which returns a shared pointer.
template<
typename NodeType,
typename std::enable_if<has_get_node_parameters_interface<
typename std::remove_pointer<NodeType>::type,
std::shared_ptr<rclcpp::node_interfaces::NodeParametersInterface>
>::value, int>::type = 0
>
const rclcpp::node_interfaces::NodeParametersInterface *
get_node_parameters_interface_from_pointer(NodeType node_pointer)
{
return node_pointer->get_node_parameters_interface().get();
}
// If NodeType has a method called get_node_parameters_interface() which returns a pointer.
template<
typename NodeType,
typename std::enable_if<has_get_node_parameters_interface<
typename std::remove_pointer<NodeType>::type,
rclcpp::node_interfaces::NodeParametersInterface *
>::value, int>::type = 0
>
const rclcpp::node_interfaces::NodeParametersInterface *
get_node_parameters_interface_from_pointer(NodeType node_pointer)
{
return node_pointer->get_node_parameters_interface();
}
// If NodeType has a method called get_node_parameters_interface() which returns a const pointer.
template<
typename NodeType,
typename std::enable_if<has_get_node_parameters_interface<
typename std::remove_pointer<NodeType>::type,
const rclcpp::node_interfaces::NodeParametersInterface *
>::value, int>::type = 0
>
const rclcpp::node_interfaces::NodeParametersInterface *
get_node_parameters_interface_from_pointer(NodeType node_pointer)
{
return node_pointer->get_node_parameters_interface();
}
// Forward shared_ptr's to const node pointer signatures.
template<
typename NodeType,
typename std::enable_if<std::is_same<
NodeType,
typename std::shared_ptr<typename std::remove_pointer<NodeType>::type::element_type> *
>::value, int>::type = 0
>
const rclcpp::node_interfaces::NodeParametersInterface *
get_node_parameters_interface_from_pointer(NodeType node_shared_pointer)
{
return get_node_parameters_interface_from_pointer(node_shared_pointer->get());
}
} // namespace detail
/// Get the NodeParametersInterface as a const pointer from a pointer to a "Node like" object.
template<
typename NodeType,
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0
>
const rclcpp::node_interfaces::NodeParametersInterface *
get_node_parameters_interface(NodeType && node_pointer)
{
// Forward pointers to detail implmentation directly.
return detail::get_node_parameters_interface_from_pointer(std::forward<NodeType>(node_pointer));
}
/// Get the NodeParametersInterface as a const pointer from a "Node like" object.
template<
typename NodeType,
typename std::enable_if<!std::is_pointer<NodeType>::value, int>::type = 0
>
const rclcpp::node_interfaces::NodeParametersInterface *
get_node_parameters_interface(NodeType && node_reference)
{
// Forward const-references to detail implmentation as a pointer.
return detail::get_node_parameters_interface_from_pointer(&node_reference);
}
} // namespace node_interfaces
} // namespace rclcpp
#endif // RCLCPP__NODE_INTERFACES__GET_NODE_PARAMETERS_INTERFACE_HPP_

View File

@@ -1,147 +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__NODE_INTERFACES__GET_NODE_TOPICS_INTERFACE_HPP_
#define RCLCPP__NODE_INTERFACES__GET_NODE_TOPICS_INTERFACE_HPP_
#include <memory>
#include <utility>
#include <type_traits>
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
/// This header provides the get_node_topics_interface() template function.
/**
* This function is useful for getting the NodeTopicsInterface pointer from
* various kinds of Node-like classes.
*
* It's able to get the NodeTopicsInterface pointer so long as the class
* has a method called ``get_node_topics_interface()`` which returns
* either a pointer (const or not) to a NodeTopicsInterface or a
* std::shared_ptr to a NodeTopicsInterface.
*/
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>
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>
static constexpr
std::false_type
check(...);
public:
using type = decltype(check<NodeType>(nullptr));
static constexpr bool value = type::value;
};
// If NodeType is a pointer to NodeTopicsInterface already (just normal function overload).
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<
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)
{
return node_pointer->get_node_topics_interface().get();
}
// If NodeType has a method called get_node_topics_interface() which returns a pointer.
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)
{
return node_pointer->get_node_topics_interface();
}
// Forward shared_ptr's to const node pointer signatures.
template<
typename NodeType,
typename std::enable_if<std::is_same<
NodeType,
typename std::shared_ptr<typename std::remove_pointer<NodeType>::type::element_type> *
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTopicsInterface *
get_node_topics_interface_from_pointer(NodeType node_shared_pointer)
{
return get_node_topics_interface_from_pointer(node_shared_pointer->get());
}
} // namespace detail
/// Get the NodeTopicsInterface as a pointer from a pointer to a "Node like" object.
template<
typename NodeType,
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTopicsInterface *
get_node_topics_interface(NodeType && node_pointer)
{
// Forward pointers to detail implmentation directly.
return detail::get_node_topics_interface_from_pointer(std::forward<NodeType>(node_pointer));
}
/// Get the NodeTopicsInterface as a pointer from a "Node like" object.
template<
typename NodeType,
typename std::enable_if<!std::is_pointer<NodeType>::value, int>::type = 0
>
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);
}
} // namespace node_interfaces
} // namespace rclcpp
#endif // RCLCPP__NODE_INTERFACES__GET_NODE_TOPICS_INTERFACE_HPP_

View File

@@ -19,11 +19,9 @@
#include <string>
#include <vector>
#include "rcl/node.h"
#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
@@ -35,15 +33,15 @@ namespace node_interfaces
class NodeBase : public NodeBaseInterface
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeBase)
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeBaseInterface)
RCLCPP_PUBLIC
NodeBase(
const std::string & node_name,
const std::string & namespace_,
rclcpp::Context::SharedPtr context,
const rcl_node_options_t & rcl_node_options,
bool use_intra_process_default);
const std::vector<std::string> & arguments,
bool use_global_arguments);
RCLCPP_PUBLIC
virtual
@@ -59,11 +57,6 @@ public:
const char *
get_namespace() const;
RCLCPP_PUBLIC
virtual
const char *
get_fully_qualified_name() const;
RCLCPP_PUBLIC
virtual
rclcpp::Context::SharedPtr
@@ -89,11 +82,6 @@ public:
std::shared_ptr<const rcl_node_t>
get_shared_rcl_node_handle() const;
RCLCPP_PUBLIC
virtual
bool
assert_liveliness() const;
RCLCPP_PUBLIC
virtual
rclcpp::callback_group::CallbackGroup::SharedPtr
@@ -129,16 +117,10 @@ public:
std::unique_lock<std::recursive_mutex>
acquire_notify_guard_condition_lock() const;
RCLCPP_PUBLIC
virtual
bool
get_use_intra_process_default() const;
private:
RCLCPP_DISABLE_COPY(NodeBase)
rclcpp::Context::SharedPtr context_;
bool use_intra_process_default_;
std::shared_ptr<rcl_node_t> node_handle_;

View File

@@ -56,13 +56,6 @@ public:
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;
/// Return the context of the node.
/** \return SharedPtr to the node's context. */
RCLCPP_PUBLIC
@@ -102,12 +95,6 @@ public:
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;
/// Create and return a callback group.
RCLCPP_PUBLIC
virtual
@@ -155,12 +142,6 @@ public:
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;
};
} // namespace node_interfaces

View File

@@ -61,6 +61,7 @@ private:
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_;
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_;
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_;
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters_;
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging_;
rclcpp::Clock::SharedPtr ros_clock_;

View File

@@ -43,6 +43,9 @@ namespace node_interfaces
// Internal struct for holding useful info about parameters
struct ParameterInfo
{
/// True if a user called declare_parameter()
bool is_declared = false;
/// Current value of the parameter.
rclcpp::ParameterValue value;
@@ -59,36 +62,24 @@ public:
RCLCPP_PUBLIC
NodeParameters(
const node_interfaces::NodeBaseInterface::SharedPtr node_base,
const node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
const node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
const node_interfaces::NodeServicesInterface::SharedPtr node_services,
const node_interfaces::NodeClockInterface::SharedPtr node_clock,
const std::vector<Parameter> & initial_parameters,
bool use_intra_process,
bool start_parameter_services,
bool start_parameter_event_publisher,
const rclcpp::QoS & parameter_event_qos,
const rclcpp::PublisherOptionsBase & parameter_event_publisher_options,
bool allow_undeclared_parameters,
bool automatically_declare_initial_parameters);
bool allow_undeclared_parameters);
RCLCPP_PUBLIC
virtual
~NodeParameters();
RCLCPP_PUBLIC
const rclcpp::ParameterValue &
void
declare_parameter(
const std::string & name,
const rclcpp::ParameterValue & default_value,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor) override;
RCLCPP_PUBLIC
void
undeclare_parameter(const std::string & name) override;
RCLCPP_PUBLIC
bool
has_parameter(const std::string & name) const override;
bool read_only) override;
RCLCPP_PUBLIC
std::vector<rcl_interfaces::msg::SetParametersResult>
@@ -132,25 +123,16 @@ public:
rcl_interfaces::msg::ListParametersResult
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const override;
RCLCPP_PUBLIC
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_initial_parameter_values() const override;
register_param_change_callback(ParametersCallbackFunction callback) override;
private:
RCLCPP_DISABLE_COPY(NodeParameters)
mutable std::mutex mutex_;
OnParametersSetCallbackType on_parameters_set_callback_ = nullptr;
ParametersCallbackFunction parameters_callback_ = nullptr;
std::map<std::string, ParameterInfo> parameters_;
@@ -164,7 +146,6 @@ private:
std::string combined_name_;
node_interfaces::NodeLoggingInterface::SharedPtr node_logging_;
node_interfaces::NodeClockInterface::SharedPtr node_clock_;
};

View File

@@ -38,53 +38,35 @@ class NodeParametersInterface
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeParametersInterface)
RCLCPP_PUBLIC
virtual
~NodeParametersInterface() = default;
/// Declare and initialize a parameter.
/**
* \sa rclcpp::Node::declare_parameter
*/
RCLCPP_PUBLIC
virtual
const rclcpp::ParameterValue &
declare_parameter(
const std::string & name,
const rclcpp::ParameterValue & default_value,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor) = 0;
/// Undeclare a parameter.
/**
* \sa rclcpp::Node::undeclare_parameter
/* This method is used to declare that a parameter exists on this node.
* If a run-time user has provided an an initial value then it will be set in this method,
* otherwise the default_value will be set.
* \param[in] name the name of the parameter
* \param[in] default_value An initial value to be used if a run-time user did not override it.
* \param[in] read_only if True then this parameter may not be changed after initialization.
* \throws std::runtime_error if parameter has already been declared.
* \throws std::runtime_error if a parameter name is invalid.
* \throws rclcpp::exceptions::InvalidParameterValueException if initial value fails to be set.
*/
RCLCPP_PUBLIC
virtual
void
undeclare_parameter(const std::string & name) = 0;
declare_parameter(
const std::string & name,
const rclcpp::ParameterValue & default_value = rclcpp::ParameterValue(),
bool read_only = false) = 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;
~NodeParametersInterface() = default;
/// 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;
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
@@ -156,34 +138,14 @@ public:
rcl_interfaces::msg::ListParametersResult
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const = 0;
using OnParametersSetCallbackType =
std::function<
rcl_interfaces::msg::SetParametersResult(const std::vector<rclcpp::Parameter> &)
>;
using ParametersCallbackFunction = std::function<
rcl_interfaces::msg::SetParametersResult(
const std::vector<rclcpp::Parameter> &)>;
using ParametersCallbackFunction [[deprecated("use OnParametersSetCallbackType instead")]] =
OnParametersSetCallbackType;
/// 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;
[[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_initial_parameter_values() const = 0;
register_param_change_callback(ParametersCallbackFunction callback) = 0;
};
} // namespace node_interfaces

View File

@@ -42,44 +42,44 @@ public:
explicit NodeTopics(rclcpp::node_interfaces::NodeBaseInterface * node_base);
RCLCPP_PUBLIC
~NodeTopics() override;
virtual
~NodeTopics();
RCLCPP_PUBLIC
virtual
rclcpp::PublisherBase::SharedPtr
create_publisher(
const std::string & topic_name,
const rclcpp::PublisherFactory & publisher_factory,
const rcl_publisher_options_t & publisher_options,
bool use_intra_process) override;
rcl_publisher_options_t & publisher_options,
bool use_intra_process);
RCLCPP_PUBLIC
virtual
void
add_publisher(
rclcpp::PublisherBase::SharedPtr publisher,
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group) override;
rclcpp::PublisherBase::SharedPtr publisher);
RCLCPP_PUBLIC
virtual
rclcpp::SubscriptionBase::SharedPtr
create_subscription(
const std::string & topic_name,
const rclcpp::SubscriptionFactory & subscription_factory,
const rcl_subscription_options_t & subscription_options,
bool use_intra_process) override;
rcl_subscription_options_t & subscription_options,
bool use_intra_process);
RCLCPP_PUBLIC
virtual
void
add_subscription(
rclcpp::SubscriptionBase::SharedPtr subscription,
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group) override;
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface() const override;
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group);
private:
RCLCPP_DISABLE_COPY(NodeTopics)
rclcpp::node_interfaces::NodeBaseInterface * node_base_;
NodeBaseInterface * node_base_;
};
} // namespace node_interfaces

View File

@@ -50,15 +50,14 @@ public:
create_publisher(
const std::string & topic_name,
const rclcpp::PublisherFactory & publisher_factory,
const rcl_publisher_options_t & publisher_options,
rcl_publisher_options_t & publisher_options,
bool use_intra_process) = 0;
RCLCPP_PUBLIC
virtual
void
add_publisher(
rclcpp::PublisherBase::SharedPtr publisher,
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group) = 0;
rclcpp::PublisherBase::SharedPtr publisher) = 0;
RCLCPP_PUBLIC
virtual
@@ -66,7 +65,7 @@ public:
create_subscription(
const std::string & topic_name,
const rclcpp::SubscriptionFactory & subscription_factory,
const rcl_subscription_options_t & subscription_options,
rcl_subscription_options_t & subscription_options,
bool use_intra_process) = 0;
RCLCPP_PUBLIC
@@ -75,11 +74,6 @@ public:
add_subscription(
rclcpp::SubscriptionBase::SharedPtr subscription,
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group) = 0;
RCLCPP_PUBLIC
virtual
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface() const = 0;
};
} // namespace node_interfaces

View File

@@ -1,330 +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__NODE_OPTIONS_HPP_
#define RCLCPP__NODE_OPTIONS_HPP_
#include <memory>
#include <string>
#include <vector>
#include "rcl/node_options.h"
#include "rclcpp/context.hpp"
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/publisher_options.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
/// Encapsulation of options for node initialization.
class NodeOptions
{
public:
/// Create NodeOptions with default values, optionally specifying the allocator to use.
/**
* Default values for the node options:
*
* - context = rclcpp::contexts::default_context::get_global_default_context()
* - arguments = {}
* - initial_parameters = {}
* - use_global_arguments = true
* - use_intra_process_comms = false
* - start_parameter_services = true
* - start_parameter_event_publisher = true
* - parameter_event_qos = rclcpp::ParameterEventQoS
* - with history setting and depth from rmw_qos_profile_parameter_events
* - parameter_event_publisher_options = rclcpp::PublisherOptionsBase
* - allow_undeclared_parameters = false
* - automatically_declare_initial_parameters = false
* - allocator = rcl_get_default_allocator()
*
* \param[in] allocator allocator to use in construction of NodeOptions.
*/
RCLCPP_PUBLIC
explicit NodeOptions(rcl_allocator_t allocator = rcl_get_default_allocator());
/// Destructor.
RCLCPP_PUBLIC
virtual
~NodeOptions() = default;
/// Copy constructor.
RCLCPP_PUBLIC
NodeOptions(const NodeOptions & other);
/// Assignment operator.
RCLCPP_PUBLIC
NodeOptions &
operator=(const NodeOptions & other);
/// Return the rcl_node_options used by the node.
/**
* This data structure is created lazily, on the first call to this function.
* Repeated calls will not regenerate it unless one of the input settings
* changed, like arguments, use_global_arguments, or the rcl allocator.
*/
RCLCPP_PUBLIC
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;
/// Set the context, return this for parameter idiom.
RCLCPP_PUBLIC
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;
/// Set the arguments, return this for parameter idiom.
/**
* These arguments are used to extract remappings used by the node and other
* settings.
*
* This will cause the internal rcl_node_options_t struct to be invalidated.
*/
RCLCPP_PUBLIC
NodeOptions &
arguments(const std::vector<std::string> & arguments);
/// Return a reference to the list of initial parameters.
RCLCPP_PUBLIC
std::vector<rclcpp::Parameter> &
initial_parameters();
RCLCPP_PUBLIC
const std::vector<rclcpp::Parameter> &
initial_parameters() const;
/// Set the initial parameters, return this for parameter idiom.
/**
* These initial parameter values are used to change the initial value
* of declared parameters within the node, overriding hard coded default
* values if necessary.
*/
RCLCPP_PUBLIC
NodeOptions &
initial_parameters(const std::vector<rclcpp::Parameter> & initial_parameters);
/// Append a single initial parameter, parameter idiom style.
template<typename ParameterT>
NodeOptions &
append_initial_parameter(const std::string & name, const ParameterT & value)
{
this->initial_parameters().emplace_back(name, rclcpp::ParameterValue(value));
return *this;
}
/// Return the use_global_arguments flag.
RCLCPP_PUBLIC
bool
use_global_arguments() const;
/// Set the use_global_arguments flag, return this for parameter idiom.
/**
* If true this will cause the node's behavior to be influenced by "global"
* arguments, i.e. arguments not targeted at specific nodes, as well as the
* arguments targeted at the current node.
*
* 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 use_intra_process_comms flag.
RCLCPP_PUBLIC
bool
use_intra_process_comms() const;
/// Set the use_intra_process_comms flag, return this for parameter idiom.
/**
* If true, messages on topics which are published and subscribed to within
* this context will go through a special intra-process communication code
* code path which can avoid serialization and deserialization, unnecessary
* copies, and achieve lower latencies in some cases.
*
* Defaults to false for now, as there are still some cases where it is not
* desirable.
*/
RCLCPP_PUBLIC
NodeOptions &
use_intra_process_comms(bool use_intra_process_comms);
/// Return the start_parameter_services flag.
RCLCPP_PUBLIC
bool
start_parameter_services() const;
/// Set the start_parameter_services flag, return this for parameter idiom.
/**
* If true, ROS services are created to allow external nodes to list, get,
* and request to set parameters of this node.
*
* If false, parameters will still work locally, but will not be accessible
* remotely.
*
* \sa start_parameter_event_publisher()
*/
RCLCPP_PUBLIC
NodeOptions &
start_parameter_services(bool start_parameter_services);
/// Return the start_parameter_event_publisher flag.
RCLCPP_PUBLIC
bool
start_parameter_event_publisher() const;
/// Set the start_parameter_event_publisher flag, return this for parameter idiom.
/**
* If true, a publisher is created on which an event message is published
* each time a parameter's state changes.
* This is used for recording and introspection, but is configurable
* separately from the other parameter services.
*/
RCLCPP_PUBLIC
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;
/// 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);
/// Return a reference to the parameter_event_publisher_options.
RCLCPP_PUBLIC
const rclcpp::PublisherOptionsBase &
parameter_event_publisher_options() const;
/// Set the parameter_event_publisher_options, return this for parameter idiom.
/**
* The QoS settings to be used for the parameter event publisher, if enabled.
*
* \todo(wjwwood): make this take/store an instance of
* rclcpp::PublisherOptionsWithAllocator<Allocator>, but to do that requires
* NodeOptions to also be templated based on the Allocator type.
*/
RCLCPP_PUBLIC
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;
/// Set the allow_undeclared_parameters, return this for parameter idiom.
/**
* If true, allow any parameter name to be set on the node without first
* being declared.
* Otherwise, setting an undeclared parameter will raise an exception.
*/
RCLCPP_PUBLIC
NodeOptions &
allow_undeclared_parameters(bool allow_undeclared_parameters);
/// Return the automatically_declare_initial_parameters flag.
RCLCPP_PUBLIC
bool
automatically_declare_initial_parameters() const;
/// Set the automatically_declare_initial_parameters, return this.
/**
* If true, automatically iterate through the node's initial parameters and
* implicitly declare any that have not already been declared.
* Otherwise, parameters passed to the node's initial_parameters, and/or the
* global initial parameter values, which are not explicitly declared will
* not appear on the node at all.
* Already declared parameters will not be re-declared, and parameters
* declared in this way will use the default constructed ParameterDescriptor.
*/
RCLCPP_PUBLIC
NodeOptions &
automatically_declare_initial_parameters(bool automatically_declare_initial_parameters);
/// Return the rcl_allocator_t to be used.
RCLCPP_PUBLIC
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);
protected:
/// Retrieve the ROS_DOMAIN_ID environment variable and populate options.
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.
/// Underlying rcl_node_options structure.
mutable std::unique_ptr<rcl_node_options_t, void (*)(rcl_node_options_t *)> node_options_;
// IMPORTANT: if any of these default values are changed, please update the
// documentation in this class.
rclcpp::Context::SharedPtr context_ {
rclcpp::contexts::default_context::get_global_default_context()};
std::vector<std::string> arguments_ {};
std::vector<rclcpp::Parameter> initial_parameters_ {};
bool use_global_arguments_ {true};
bool use_intra_process_comms_ {false};
bool start_parameter_services_ {true};
bool start_parameter_event_publisher_ {true};
rclcpp::QoS parameter_event_qos_ = rclcpp::ParameterEventsQoS(
rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events)
);
rclcpp::PublisherOptionsBase parameter_event_publisher_options_ = rclcpp::PublisherOptionsBase();
bool allow_undeclared_parameters_ {false};
bool automatically_declare_initial_parameters_ {false};
rcl_allocator_t allocator_ {rcl_get_default_allocator()};
};
} // namespace rclcpp
#endif // RCLCPP__NODE_OPTIONS_HPP_

View File

@@ -51,37 +51,21 @@ get_value_helper(const rclcpp::Parameter * parameter);
class Parameter
{
public:
/// Construct with an empty name and a parameter value of type rclcpp::PARAMETER_NOT_SET.
RCLCPP_PUBLIC
Parameter();
/// Construct with given name and a parameter value of type rclcpp::PARAMETER_NOT_SET.
RCLCPP_PUBLIC
explicit Parameter(const std::string & name);
/// Construct with given name and given parameter value.
RCLCPP_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)
explicit 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;
/// Not equal operator.
RCLCPP_PUBLIC
bool
operator!=(const Parameter & rhs) const;
RCLCPP_PUBLIC
ParameterType
get_type() const;
@@ -207,7 +191,7 @@ 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).
// Use this labmda to ensure it's a const reference being returned (and not a copy).
auto type_enforcing_lambda =
[&parameter]() -> const rclcpp::Parameter & {
return *parameter;

View File

@@ -110,33 +110,38 @@ public:
template<
typename CallbackT,
typename AllocatorT = std::allocator<void>>
typename Alloc = std::allocator<void>,
typename SubscriptionT =
rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent, Alloc>>
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_default))
),
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
))
on_parameter_event(CallbackT && callback)
{
return rclcpp::create_subscription<rcl_interfaces::msg::ParameterEvent>(
this->node_topics_interface_,
using rclcpp::message_memory_strategy::MessageMemoryStrategy;
auto msg_mem_strat =
MessageMemoryStrategy<rcl_interfaces::msg::ParameterEvent, Alloc>::create_default();
using rcl_interfaces::msg::ParameterEvent;
return rclcpp::create_subscription<
ParameterEvent, CallbackT, Alloc, ParameterEvent, SubscriptionT>(
this->node_topics_interface_.get(),
"parameter_events",
qos,
std::forward<CallbackT>(callback),
options);
rmw_qos_profile_default,
nullptr, // group,
false, // ignore_local_publications,
false, // use_intra_process_comms_,
msg_mem_strat,
std::make_shared<Alloc>());
}
RCLCPP_PUBLIC
bool
service_is_ready() const;
template<typename RepT = int64_t, typename RatioT = std::milli>
template<typename RatioT = std::milli>
bool
wait_for_service(
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
std::chrono::duration<int64_t, RatioT> timeout = std::chrono::duration<int64_t, RatioT>(-1))
{
return wait_for_service_nanoseconds(
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
@@ -149,7 +154,7 @@ protected:
wait_for_service_nanoseconds(std::chrono::nanoseconds timeout);
private:
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_interface_;
const 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_;
@@ -276,10 +281,10 @@ public:
return async_parameters_client_->service_is_ready();
}
template<typename RepT = int64_t, typename RatioT = std::milli>
template<typename RatioT = std::milli>
bool
wait_for_service(
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
std::chrono::duration<int64_t, RatioT> timeout = std::chrono::duration<int64_t, RatioT>(-1))
{
return async_parameters_client_->wait_for_service(timeout);
}

View File

@@ -43,7 +43,7 @@ public:
explicit ParameterService(
const std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
const std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
rclcpp::node_interfaces::NodeParametersInterface * node_params,
node_interfaces::NodeParametersInterface * node_params,
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters);
private:

View File

@@ -130,21 +130,10 @@ public:
rcl_interfaces::msg::ParameterValue
to_value_msg() const;
/// Equal operator.
RCLCPP_PUBLIC
bool
operator==(const ParameterValue & rhs) const;
/// Not equal operator.
RCLCPP_PUBLIC
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
typename std::enable_if<type == ParameterType::PARAMETER_BOOL, bool>::type
get() const
{
if (value_.type != rcl_interfaces::msg::ParameterType::PARAMETER_BOOL) {
@@ -154,8 +143,7 @@ public:
}
template<ParameterType type>
constexpr
typename std::enable_if<type == ParameterType::PARAMETER_INTEGER, const int64_t &>::type
typename std::enable_if<type == ParameterType::PARAMETER_INTEGER, int64_t>::type
get() const
{
if (value_.type != rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER) {
@@ -165,8 +153,7 @@ public:
}
template<ParameterType type>
constexpr
typename std::enable_if<type == ParameterType::PARAMETER_DOUBLE, const double &>::type
typename std::enable_if<type == ParameterType::PARAMETER_DOUBLE, double>::type
get() const
{
if (value_.type != rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE) {
@@ -176,7 +163,6 @@ public:
}
template<ParameterType type>
constexpr
typename std::enable_if<type == ParameterType::PARAMETER_STRING, const std::string &>::type
get() const
{
@@ -187,7 +173,6 @@ public:
}
template<ParameterType type>
constexpr
typename std::enable_if<
type == ParameterType::PARAMETER_BYTE_ARRAY, const std::vector<uint8_t> &>::type
get() const
@@ -199,7 +184,6 @@ public:
}
template<ParameterType type>
constexpr
typename std::enable_if<
type == ParameterType::PARAMETER_BOOL_ARRAY, const std::vector<bool> &>::type
get() const
@@ -211,7 +195,6 @@ public:
}
template<ParameterType type>
constexpr
typename std::enable_if<
type == ParameterType::PARAMETER_INTEGER_ARRAY, const std::vector<int64_t> &>::type
get() const
@@ -223,7 +206,6 @@ public:
}
template<ParameterType type>
constexpr
typename std::enable_if<
type == ParameterType::PARAMETER_DOUBLE_ARRAY, const std::vector<double> &>::type
get() const
@@ -235,7 +217,6 @@ public:
}
template<ParameterType type>
constexpr
typename std::enable_if<
type == ParameterType::PARAMETER_STRING_ARRAY, const std::vector<std::string> &>::type
get() const
@@ -249,32 +230,28 @@ 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
typename std::enable_if<std::is_same<type, bool>::value, 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
std::is_integral<type>::value && !std::is_same<type, bool>::value, 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
typename std::enable_if<std::is_floating_point<type>::value, 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
{
@@ -282,7 +259,6 @@ public:
}
template<typename type>
constexpr
typename std::enable_if<
std::is_convertible<
type, const std::vector<uint8_t> &>::value, const std::vector<uint8_t> &>::type
@@ -292,7 +268,6 @@ public:
}
template<typename type>
constexpr
typename std::enable_if<
std::is_convertible<
type, const std::vector<bool> &>::value, const std::vector<bool> &>::type
@@ -302,7 +277,6 @@ public:
}
template<typename type>
constexpr
typename std::enable_if<
std::is_convertible<
type, const std::vector<int64_t> &>::value, const std::vector<int64_t> &>::type
@@ -312,7 +286,6 @@ public:
}
template<typename type>
constexpr
typename std::enable_if<
std::is_convertible<
type, const std::vector<double> &>::value, const std::vector<double> &>::type
@@ -322,7 +295,6 @@ public:
}
template<typename type>
constexpr
typename std::enable_if<
std::is_convertible<
type, const std::vector<std::string> &>::value, const std::vector<std::string> &>::type

View File

@@ -23,7 +23,6 @@
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include "rcl/error_handling.h"
#include "rcl/publisher.h"
@@ -32,15 +31,125 @@
#include "rclcpp/allocator/allocator_common.hpp"
#include "rclcpp/allocator/allocator_deleter.hpp"
#include "rclcpp/intra_process_manager.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/publisher_base.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
// Forward declaration is used for friend statement.
namespace node_interfaces
{
class NodeTopicsInterface;
}
class PublisherBase
{
friend ::rclcpp::node_interfaces::NodeTopicsInterface;
public:
RCLCPP_SMART_PTR_DEFINITIONS(PublisherBase)
/// Default constructor.
/**
* Typically, a publisher is not created through this method, but instead is created through a
* call to `Node::create_publisher`.
* \param[in] node_base A pointer to the NodeBaseInterface for the parent node.
* \param[in] topic The topic that this publisher publishes on.
* \param[in] type_support The type support structure for the type to be published.
* \param[in] publisher_options QoS settings for this publisher.
*/
RCLCPP_PUBLIC
PublisherBase(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const std::string & topic,
const rosidl_message_type_support_t & type_support,
const rcl_publisher_options_t & publisher_options);
RCLCPP_PUBLIC
virtual ~PublisherBase();
/// Get the topic that this publisher publishes on.
/** \return The topic name. */
RCLCPP_PUBLIC
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;
/// 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;
/// 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();
/// Get the rcl publisher handle.
/** \return The rcl publisher handle. */
RCLCPP_PUBLIC
const rcl_publisher_t *
get_publisher_handle() const;
/// Compare this publisher to a gid.
/**
* Note that this function calls the next function.
* \param[in] gid Reference to a gid.
* \return True if the publisher's gid matches the input.
*/
RCLCPP_PUBLIC
bool
operator==(const rmw_gid_t & gid) const;
/// Compare this publisher to a pointer gid.
/**
* A wrapper for comparing this publisher's gid to the input using rmw_compare_gids_equal.
* \param[in] gid A pointer to a gid.
* \return True if this publisher's gid matches the input.
*/
RCLCPP_PUBLIC
bool
operator==(const rmw_gid_t * gid) const;
using StoreMessageCallbackT = std::function<uint64_t(uint64_t, void *, const std::type_info &)>;
/// Implementation utility function used to setup intra process publishing after creation.
RCLCPP_PUBLIC
void
setup_intra_process(
uint64_t intra_process_publisher_id,
StoreMessageCallbackT callback,
const rcl_publisher_options_t & intra_process_options);
protected:
std::shared_ptr<rcl_node_t> rcl_node_handle_;
rcl_publisher_t publisher_handle_ = rcl_get_zero_initialized_publisher();
rcl_publisher_t intra_process_publisher_handle_ = rcl_get_zero_initialized_publisher();
uint64_t intra_process_publisher_id_;
StoreMessageCallbackT store_intra_process_message_;
rmw_gid_t rmw_gid_;
rmw_gid_t intra_process_rmw_gid_;
};
/// A publisher publishes messages of any type to a topic.
template<typename MessageT, typename Alloc = std::allocator<void>>
class Publisher : public PublisherBase
@@ -50,7 +159,6 @@ public:
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, Alloc>)
@@ -58,7 +166,6 @@ public:
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const std::string & topic,
const rcl_publisher_options_t & publisher_options,
const PublisherEventCallbacks & event_callbacks,
const std::shared_ptr<MessageAlloc> & allocator)
: PublisherBase(
node_base,
@@ -68,99 +175,108 @@ public:
message_allocator_(allocator)
{
allocator::set_allocator_for_deleter(&message_deleter_, message_allocator_.get());
if (event_callbacks.deadline_callback) {
this->add_event_handler(event_callbacks.deadline_callback,
RCL_PUBLISHER_OFFERED_DEADLINE_MISSED);
}
if (event_callbacks.liveliness_callback) {
this->add_event_handler(event_callbacks.liveliness_callback,
RCL_PUBLISHER_LIVELINESS_LOST);
}
}
virtual ~Publisher()
{}
mapped_ring_buffer::MappedRingBufferBase::SharedPtr
make_mapped_ring_buffer(size_t size) const override
{
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.
/**
* 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)
publish(std::unique_ptr<MessageT, MessageDeleter> & msg)
{
if (!intra_process_is_enabled_) {
this->do_inter_process_publish(msg.get());
return;
}
// If an interprocess subscription exist, then the unique_ptr is promoted
// to a shared_ptr and published.
// This allows doing the intraprocess publish first and then doing the
// 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) {
shared_msg = std::move(msg);
message_seq =
store_intra_process_message(intra_process_publisher_id_, shared_msg);
this->do_inter_process_publish(msg.get());
if (store_intra_process_message_) {
// Take the pointer from the unique_msg, release it and pass as a void *
// to the ipm. The ipm should then capture it again as a unique_ptr of
// the correct type.
// TODO(wjwwood):
// investigate how to transfer the custom deleter (if there is one)
// from the incoming unique_ptr through to the ipm's unique_ptr.
// See: http://stackoverflow.com/questions/11002641/dynamic-casting-for-unique-ptr
MessageT * msg_ptr = msg.get();
msg.release();
uint64_t message_seq =
store_intra_process_message_(intra_process_publisher_id_, msg_ptr, typeid(MessageT));
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);
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(&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;
}
}
}
if (RCL_RET_OK != status) {
rclcpp::exceptions::throw_from_rcl_error(status, "failed to publish intra process message");
}
} else {
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());
// Always destroy the message, even if we don't consume it, for consistency.
msg.reset();
}
}
// 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(const std::shared_ptr<MessageT> & msg)
{
publish(*msg);
// Avoid allocating when not using intra process.
if (!store_intra_process_message_) {
// In this case we're not using intra process.
return this->do_inter_process_publish(msg.get());
}
// Otherwise we have to allocate memory in a unique_ptr and pass it along.
// TODO(wjwwood):
// The intra process manager should probably also be able to store
// shared_ptr's and do the "smart" thing based on other intra process
// subscriptions. For now call the other publish().
auto ptr = MessageAllocTraits::allocate(*message_allocator_.get(), 1);
MessageAllocTraits::construct(*message_allocator_.get(), ptr, *msg.get());
MessageUniquePtr unique_msg(ptr, message_deleter_);
return this->publish(unique_msg);
}
virtual void
publish(std::shared_ptr<const MessageT> msg)
{
// Avoid allocating when not using intra process.
if (!store_intra_process_message_) {
// In this case we're not using intra process.
return this->do_inter_process_publish(msg.get());
}
// Otherwise we have to allocate memory in a unique_ptr and pass it along.
// TODO(wjwwood):
// The intra process manager should probably also be able to store
// shared_ptr's and do the "smart" thing based on other intra process
// subscriptions. For now call the other publish().
auto ptr = MessageAllocTraits::allocate(*message_allocator_.get(), 1);
MessageAllocTraits::construct(*message_allocator_.get(), ptr, *msg.get());
MessageUniquePtr unique_msg(ptr, message_deleter_);
return this->publish(unique_msg);
}
virtual void
publish(const MessageT & msg)
{
// Avoid allocating when not using intra process.
if (!intra_process_is_enabled_) {
if (!store_intra_process_message_) {
// In this case we're not using intra process.
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 = 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));
return this->publish(unique_msg);
}
// Skip deprecated attribute in windows, as it raise a warning in template specialization.
#if !defined(_WIN32)
[[deprecated(
"Use publish(*msg). Check against nullptr before calling if necessary.")]]
#endif
virtual void
publish(const MessageT * msg)
{
@@ -170,32 +286,23 @@ public:
return this->publish(*msg);
}
void
publish(const rcl_serialized_message_t & serialized_msg)
{
return this->do_serialized_publish(&serialized_msg);
}
// Skip deprecated attribute in windows, as it raise a warning in template specialization.
#if !defined(_WIN32)
[[deprecated(
"Use publish(*serialized_msg). Check against nullptr before calling if necessary.")]]
#endif
void
publish(const rcl_serialized_message_t * serialized_msg)
{
return this->do_serialized_publish(serialized_msg);
if (store_intra_process_message_) {
// TODO(Karsten1987): support serialized message passed by intraprocess
throw std::runtime_error("storing serialized messages in intra process is not supported yet");
}
auto status = rcl_publish_serialized_message(&publisher_handle_, serialized_msg);
if (RCL_RET_OK != status) {
rclcpp::exceptions::throw_from_rcl_error(status, "failed to publish serialized message");
}
}
// 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());
return this->publish(serialized_msg.get());
}
std::shared_ptr<MessageAlloc> get_allocator() const
@@ -207,7 +314,7 @@ protected:
void
do_inter_process_publish(const MessageT * msg)
{
auto status = rcl_publish(&publisher_handle_, msg, nullptr);
auto status = rcl_publish(&publisher_handle_, msg);
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_)) {
@@ -223,77 +330,6 @@ protected:
}
}
void
do_serialized_publish(const rcl_serialized_message_t * serialized_msg)
{
if (intra_process_is_enabled_) {
// TODO(Karsten1987): support serialized message passed by intraprocess
throw std::runtime_error("storing serialized messages in intra process is not supported yet");
}
auto status = rcl_publish_serialized_message(&publisher_handle_, serialized_msg, nullptr);
if (RCL_RET_OK != status) {
rclcpp::exceptions::throw_from_rcl_error(status, "failed to publish serialized message");
}
}
void
do_intra_process_publish(uint64_t message_seq)
{
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(&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;
}
}
}
if (RCL_RET_OK != status) {
rclcpp::exceptions::throw_from_rcl_error(status, "failed to publish intra process message");
}
}
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");
}
if (!msg) {
throw std::runtime_error("cannot publisher msg which is a null pointer");
}
uint64_t message_seq =
ipm->template store_intra_process_message<MessageT, Alloc>(publisher_id, msg);
return message_seq;
}
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");
}
if (!msg) {
throw std::runtime_error("cannot publisher msg which is a null pointer");
}
uint64_t message_seq =
ipm->template store_intra_process_message<MessageT, Alloc>(publisher_id, std::move(msg));
return message_seq;
}
std::shared_ptr<MessageAlloc> message_allocator_;
MessageDeleter message_deleter_;

View File

@@ -1,232 +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__PUBLISHER_BASE_HPP_
#define RCLCPP__PUBLISHER_BASE_HPP_
#include <rmw/error_handling.h>
#include <rmw/rmw.h>
#include <functional>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#include "rcl/publisher.h"
#include "rclcpp/macros.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
{
class NodeBaseInterface;
class NodeTopicsInterface;
}
namespace intra_process_manager
{
/**
* IntraProcessManager is forward declared here, avoiding a circular inclusion between
* `intra_process_manager.hpp` and `publisher_base.hpp`.
*/
class IntraProcessManager;
}
class PublisherBase
{
friend ::rclcpp::node_interfaces::NodeTopicsInterface;
public:
RCLCPP_SMART_PTR_DEFINITIONS(PublisherBase)
/// Default constructor.
/**
* Typically, a publisher is not created through this method, but instead is created through a
* call to `Node::create_publisher`.
* \param[in] node_base A pointer to the NodeBaseInterface for the parent node.
* \param[in] topic The topic that this publisher publishes on.
* \param[in] type_support The type support structure for the type to be published.
* \param[in] publisher_options QoS settings for this publisher.
*/
RCLCPP_PUBLIC
PublisherBase(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const std::string & topic,
const rosidl_message_type_support_t & type_support,
const rcl_publisher_options_t & publisher_options);
RCLCPP_PUBLIC
virtual ~PublisherBase();
/// Get the topic that this publisher publishes on.
/** \return The topic name. */
RCLCPP_PUBLIC
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;
/// 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;
/// 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();
/// Get the rcl publisher handle.
/** \return The rcl publisher handle. */
RCLCPP_PUBLIC
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;
/// Get subscription count
/** \return The number of subscriptions. */
RCLCPP_PUBLIC
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;
/// Manually assert that this Publisher is alive (for RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC).
/**
* If the rmw Liveliness policy is set to RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC, the creator
* of this publisher may manually call `assert_liveliness` at some point in time to signal to the
* rest of the system that this Node is still alive.
*
* \return `true` if the liveliness was asserted successfully, otherwise `false`
*/
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
bool
assert_liveliness() const;
/// Get the actual QoS settings, after the defaults have been determined.
/**
* The actual configuration applied when using RMW_QOS_POLICY_*_SYSTEM_DEFAULT
* can only be resolved after the creation of the publisher, and it
* depends on the underlying rmw implementation.
* If the underlying setting in use can't be represented in ROS terms,
* it will be set to RMW_QOS_POLICY_*_UNKNOWN.
* May throw runtime_error when an unexpected error occurs.
* \return The actual qos settings.
*/
RCLCPP_PUBLIC
rmw_qos_profile_t
get_actual_qos() const;
/// Compare this publisher to a gid.
/**
* Note that this function calls the next function.
* \param[in] gid Reference to a gid.
* \return True if the publisher's gid matches the input.
*/
RCLCPP_PUBLIC
bool
operator==(const rmw_gid_t & gid) const;
/// Compare this publisher to a pointer gid.
/**
* A wrapper for comparing this publisher's gid to the input using rmw_compare_gids_equal.
* \param[in] gid A pointer to a gid.
* \return True if this publisher's gid matches the input.
*/
RCLCPP_PUBLIC
bool
operator==(const rmw_gid_t * gid) const;
using IntraProcessManagerSharedPtr =
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(
uint64_t intra_process_publisher_id,
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)
{
auto handler = std::make_shared<QOSEventHandler<EventCallbackT>>(
callback,
rcl_publisher_event_init,
&publisher_handle_,
event_type);
event_handlers_.emplace_back(handler);
}
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::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
#endif // RCLCPP__PUBLISHER_BASE_HPP_

View File

@@ -49,38 +49,94 @@ struct PublisherFactory
rclcpp::PublisherBase::SharedPtr(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const std::string & topic_name,
const rcl_publisher_options_t & publisher_options)>;
rcl_publisher_options_t & publisher_options)>;
PublisherFactoryFunction create_typed_publisher;
// Adds the PublisherBase to the intraprocess manager with the correctly
// templated call to IntraProcessManager::store_intra_process_message.
using AddPublisherToIntraProcessManagerFunction = std::function<
uint64_t(
rclcpp::intra_process_manager::IntraProcessManager * ipm,
rclcpp::PublisherBase::SharedPtr publisher)>;
AddPublisherToIntraProcessManagerFunction add_publisher_to_intra_process_manager;
// Creates the callback function which is called on each
// PublisherT::publish() and which handles the intra process transmission of
// the message being published.
using SharedPublishCallbackFactoryFunction = std::function<
rclcpp::PublisherBase::StoreMessageCallbackT(
rclcpp::intra_process_manager::IntraProcessManager::SharedPtr ipm)>;
SharedPublishCallbackFactoryFunction create_shared_publish_callback;
};
/// Return a PublisherFactory with functions setup for creating a PublisherT<MessageT, Alloc>.
template<typename MessageT, typename Alloc, typename PublisherT>
PublisherFactory
create_publisher_factory(
const PublisherEventCallbacks & event_callbacks,
std::shared_ptr<Alloc> allocator)
create_publisher_factory(std::shared_ptr<Alloc> allocator)
{
PublisherFactory factory;
// factory function that creates a MessageT specific PublisherT
factory.create_typed_publisher =
[event_callbacks, allocator](
[allocator](
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const std::string & topic_name,
const rcl_publisher_options_t & publisher_options
) -> std::shared_ptr<PublisherT>
rcl_publisher_options_t & publisher_options) -> std::shared_ptr<PublisherT>
{
auto options_copy = publisher_options;
auto message_alloc = std::make_shared<typename PublisherT::MessageAlloc>(*allocator.get());
options_copy.allocator = allocator::get_rcl_allocator<MessageT>(*message_alloc.get());
publisher_options.allocator = allocator::get_rcl_allocator<MessageT>(*message_alloc.get());
return std::make_shared<PublisherT>(
node_base,
topic_name,
options_copy,
event_callbacks,
message_alloc);
return std::make_shared<PublisherT>(node_base, topic_name, publisher_options, message_alloc);
};
// function to add a publisher to the intra process manager
factory.add_publisher_to_intra_process_manager =
[](
rclcpp::intra_process_manager::IntraProcessManager * ipm,
rclcpp::PublisherBase::SharedPtr publisher) -> uint64_t
{
return ipm->add_publisher<MessageT, Alloc>(std::dynamic_pointer_cast<PublisherT>(publisher));
};
// function to create a shared publish callback std::function
using StoreMessageCallbackT = rclcpp::PublisherBase::StoreMessageCallbackT;
factory.create_shared_publish_callback =
[](rclcpp::intra_process_manager::IntraProcessManager::SharedPtr ipm) -> StoreMessageCallbackT
{
rclcpp::intra_process_manager::IntraProcessManager::WeakPtr weak_ipm = ipm;
// this function is called on each call to publish() and handles storing
// of the published message in the intra process manager
auto shared_publish_callback =
[weak_ipm](uint64_t publisher_id, void * msg, const std::type_info & type_info) -> uint64_t
{
auto ipm = weak_ipm.lock();
if (!ipm) {
// TODO(wjwwood): should this just return silently? Or maybe return with a warning?
throw std::runtime_error(
"intra process publish called after destruction of intra process manager");
}
if (!msg) {
throw std::runtime_error("cannot publisher msg which is a null pointer");
}
auto & message_type_info = typeid(MessageT);
if (message_type_info != type_info) {
throw std::runtime_error(
std::string("published type '") + type_info.name() +
"' is incompatible from the publisher type '" + message_type_info.name() + "'");
}
MessageT * typed_message_ptr = static_cast<MessageT *>(msg);
using MessageDeleter = typename Publisher<MessageT, Alloc>::MessageDeleter;
std::unique_ptr<MessageT, MessageDeleter> unique_msg(typed_message_ptr);
uint64_t message_seq =
ipm->store_intra_process_message<MessageT, Alloc>(publisher_id, unique_msg);
return message_seq;
};
return shared_publish_callback;
};
// return the factory now that it is populated

View File

@@ -1,78 +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__PUBLISHER_OPTIONS_HPP_
#define RCLCPP__PUBLISHER_OPTIONS_HPP_
#include <memory>
#include <string>
#include <vector>
#include "rclcpp/callback_group.hpp"
#include "rclcpp/intra_process_setting.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rcl/publisher.h"
namespace rclcpp
{
/// Non-templated part of PublisherOptionsWithAllocator<Allocator>.
struct PublisherOptionsBase
{
/// Setting to explicitly set intraprocess communications.
IntraProcessSetting use_intra_process_comm = IntraProcessSetting::NodeDefault;
/// Callbacks for various events related to publishers.
PublisherEventCallbacks event_callbacks;
/// Callback group in which the waitable items from the publisher should be placed.
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group;
};
/// Structure containing optional configuration for Publishers.
template<typename Allocator>
struct PublisherOptionsWithAllocator : public PublisherOptionsBase
{
/// Optional custom allocator.
std::shared_ptr<Allocator> allocator = nullptr;
PublisherOptionsWithAllocator<Allocator>() {}
/// Constructor using base class as input.
explicit PublisherOptionsWithAllocator(const PublisherOptionsBase & publisher_options_base)
: PublisherOptionsBase(publisher_options_base)
{}
/// Convert this class, and a rclcpp::QoS, into an rcl_publisher_options_t.
template<typename MessageT>
rcl_publisher_options_t
to_rcl_publisher_options(const rclcpp::QoS & qos) const
{
rcl_publisher_options_t result;
using AllocatorTraits = std::allocator_traits<Allocator>;
using MessageAllocatorT = typename AllocatorTraits::template rebind_alloc<MessageT>;
auto message_alloc = std::make_shared<MessageAllocatorT>(*allocator.get());
result.allocator = allocator::get_rcl_allocator<MessageT>(*message_alloc);
result.qos = qos.get_rmw_qos_profile();
return result;
}
};
using PublisherOptions = PublisherOptionsWithAllocator<std::allocator<void>>;
} // namespace rclcpp
#endif // RCLCPP__PUBLISHER_OPTIONS_HPP_

View File

@@ -1,203 +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__QOS_HPP_
#define RCLCPP__QOS_HPP_
#include <rmw/qos_profiles.h>
#include <rmw/types.h>
#include "rclcpp/duration.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
/// QoS initialization values, cannot be created directly, use KeepAll or KeepLast instead.
struct RCLCPP_PUBLIC QoSInitialization
{
rmw_qos_history_policy_t history_policy;
size_t depth;
/// Constructor which takes both a history policy and a depth (even if it would be unused).
QoSInitialization(rmw_qos_history_policy_t history_policy_arg, size_t depth_arg);
/// Create a QoSInitialization from an existing rmw_qos_profile_t, using its history and depth.
static
QoSInitialization
from_rmw(const rmw_qos_profile_t & rmw_qos);
};
/// Use to initialize the QoS with the keep_all history setting.
struct RCLCPP_PUBLIC KeepAll : public rclcpp::QoSInitialization
{
KeepAll();
};
/// Use to initialize the QoS with the keep_last history setting and the given depth.
struct RCLCPP_PUBLIC KeepLast : public rclcpp::QoSInitialization
{
explicit KeepLast(size_t depth);
};
/// Encapsulation of Quality of Service settings.
class RCLCPP_PUBLIC QoS
{
public:
/// Constructor which allows you to construct a QoS by giving the only required settings.
explicit
QoS(
const QoSInitialization & qos_initialization,
const rmw_qos_profile_t & initial_profile = rmw_qos_profile_default);
/// Conversion constructor to ease construction in the common case of just specifying depth.
/**
* Convenience constructor, equivalent to QoS(KeepLast(history_depth)).
*/
// cppcheck-suppress noExplicitConstructor
QoS(size_t history_depth); // NOLINT(runtime/explicit): conversion constructor
/// Return the rmw qos profile.
rmw_qos_profile_t &
get_rmw_qos_profile();
/// Return the rmw qos profile.
const rmw_qos_profile_t &
get_rmw_qos_profile() const;
/// Set the history policy.
QoS &
history(rmw_qos_history_policy_t history);
/// Set the history to keep last.
QoS &
keep_last(size_t depth);
/// Set the history to keep all.
QoS &
keep_all();
/// Set the reliability setting.
QoS &
reliability(rmw_qos_reliability_policy_t reliability);
/// Set the reliability setting to reliable.
QoS &
reliable();
/// Set the reliability setting to best effort.
QoS &
best_effort();
/// Set the durability setting.
QoS &
durability(rmw_qos_durability_policy_t durability);
/// Set the durability setting to volatile.
QoS &
volitile();
/// Set the durability setting to transient local.
QoS &
transient_local();
/// Set the deadline setting.
QoS &
deadline(rmw_time_t deadline);
/// Set the deadline setting, rclcpp::Duration.
QoS &
deadline(const rclcpp::Duration & deadline);
/// Set the lifespan setting.
QoS &
lifespan(rmw_time_t lifespan);
/// Set the lifespan setting, rclcpp::Duration.
QoS &
lifespan(const rclcpp::Duration & lifespan);
/// Set the liveliness setting.
QoS &
liveliness(rmw_qos_liveliness_policy_t liveliness);
/// Set the liveliness_lease_duration setting.
QoS &
liveliness_lease_duration(rmw_time_t liveliness_lease_duration);
/// Set the liveliness_lease_duration setting, rclcpp::Duration.
QoS &
liveliness_lease_duration(const rclcpp::Duration & liveliness_lease_duration);
/// Set the avoid_ros_namespace_conventions setting.
QoS &
avoid_ros_namespace_conventions(bool avoid_ros_namespace_conventions);
private:
rmw_qos_profile_t rmw_qos_profile_;
};
class RCLCPP_PUBLIC SensorDataQoS : public QoS
{
public:
explicit
SensorDataQoS(
const QoSInitialization & qos_initialization = (
QoSInitialization::from_rmw(rmw_qos_profile_sensor_data)
));
};
class RCLCPP_PUBLIC ParametersQoS : public QoS
{
public:
explicit
ParametersQoS(
const QoSInitialization & qos_initialization = (
QoSInitialization::from_rmw(rmw_qos_profile_parameters)
));
};
class RCLCPP_PUBLIC ServicesQoS : public QoS
{
public:
explicit
ServicesQoS(
const QoSInitialization & qos_initialization = (
QoSInitialization::from_rmw(rmw_qos_profile_services_default)
));
};
class RCLCPP_PUBLIC ParameterEventsQoS : public QoS
{
public:
explicit
ParameterEventsQoS(
const QoSInitialization & qos_initialization = (
QoSInitialization::from_rmw(rmw_qos_profile_parameter_events)
));
};
class RCLCPP_PUBLIC SystemDefaultsQoS : public QoS
{
public:
explicit
SystemDefaultsQoS(
const QoSInitialization & qos_initialization = (
QoSInitialization::from_rmw(rmw_qos_profile_system_default)
));
};
} // namespace rclcpp
#endif // RCLCPP__QOS_HPP_

View File

@@ -1,126 +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__QOS_EVENT_HPP_
#define RCLCPP__QOS_EVENT_HPP_
#include <functional>
#include "rcl/error_handling.h"
#include "rcutils/logging_macros.h"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/function_traits.hpp"
#include "rclcpp/waitable.hpp"
namespace rclcpp
{
using QOSDeadlineRequestedInfo = rmw_requested_deadline_missed_status_t;
using QOSDeadlineOfferedInfo = rmw_offered_deadline_missed_status_t;
using QOSLivelinessChangedInfo = rmw_liveliness_changed_status_t;
using QOSLivelinessLostInfo = rmw_liveliness_lost_status_t;
using QOSDeadlineRequestedCallbackType = std::function<void (QOSDeadlineRequestedInfo &)>;
using QOSDeadlineOfferedCallbackType = std::function<void (QOSDeadlineOfferedInfo &)>;
using QOSLivelinessChangedCallbackType = std::function<void (QOSLivelinessChangedInfo &)>;
using QOSLivelinessLostCallbackType = std::function<void (QOSLivelinessLostInfo &)>;
/// Contains callbacks for various types of events a Publisher can receive from the middleware.
struct PublisherEventCallbacks
{
QOSDeadlineOfferedCallbackType deadline_callback;
QOSLivelinessLostCallbackType liveliness_callback;
};
/// Contains callbacks for non-message events that a Subscription can receive from the middleware.
struct SubscriptionEventCallbacks
{
QOSDeadlineRequestedCallbackType deadline_callback;
QOSLivelinessChangedCallbackType liveliness_callback;
};
class QOSEventHandlerBase : public Waitable
{
public:
RCLCPP_PUBLIC
virtual ~QOSEventHandlerBase();
/// Get the number of ready events
RCLCPP_PUBLIC
size_t
get_number_of_ready_events() override;
/// Add the Waitable to a wait set.
RCLCPP_PUBLIC
bool
add_to_wait_set(rcl_wait_set_t * wait_set) override;
/// Check if the Waitable is ready.
RCLCPP_PUBLIC
bool
is_ready(rcl_wait_set_t * wait_set) override;
protected:
rcl_event_t event_handle_;
size_t wait_set_event_index_;
};
template<typename EventCallbackT>
class QOSEventHandler : public QOSEventHandlerBase
{
public:
template<typename InitFuncT, typename ParentHandleT, typename EventTypeEnum>
QOSEventHandler(
const EventCallbackT & callback,
InitFuncT init_func,
ParentHandleT parent_handle,
EventTypeEnum event_type)
: event_callback_(callback)
{
event_handle_ = rcl_get_zero_initialized_event();
rcl_ret_t ret = init_func(&event_handle_, parent_handle, event_type);
if (ret != RCL_RET_OK) {
rclcpp::exceptions::throw_from_rcl_error(ret, "could not create event");
}
}
/// Execute any entities of the Waitable that are ready.
void
execute() override
{
EventCallbackInfoT callback_info;
rcl_ret_t ret = rcl_take_event(&event_handle_, &callback_info);
if (ret != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't take event info: %s", rcl_get_error_string().str);
return;
}
event_callback_(callback_info);
}
private:
using EventCallbackInfoT = typename std::remove_reference<typename
rclcpp::function_traits::function_traits<EventCallbackT>::template argument_type<0>>::type;
EventCallbackT event_callback_;
};
} // namespace rclcpp
#endif // RCLCPP__QOS_EVENT_HPP_

View File

@@ -430,15 +430,6 @@ public:
return number_of_services;
}
size_t number_of_ready_events() const
{
size_t number_of_events = 0;
for (auto waitable : waitable_handles_) {
number_of_events += waitable->get_number_of_ready_events();
}
return number_of_events;
}
size_t number_of_ready_clients() const
{
size_t number_of_clients = client_handles_.size();

View File

@@ -23,8 +23,6 @@
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include "rcl/error_handling.h"
#include "rcl/subscription.h"
@@ -34,15 +32,11 @@
#include "rclcpp/any_subscription_callback.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/expand_topic_or_service_name.hpp"
#include "rclcpp/intra_process_manager.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/message_memory_strategy.hpp"
#include "rclcpp/subscription_base.hpp"
#include "rclcpp/subscription_traits.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/waitable.hpp"
namespace rclcpp
{
@@ -52,6 +46,101 @@ namespace node_interfaces
class NodeTopicsInterface;
} // namespace node_interfaces
/// Virtual base class for subscriptions. This pattern allows us to iterate over different template
/// specializations of Subscription, among other things.
class SubscriptionBase
{
public:
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(SubscriptionBase)
/// Default constructor.
/**
* \param[in] node_handle The rcl representation of the node that owns this subscription.
* \param[in] type_support_handle rosidl type support struct, for the Message type of the topic.
* \param[in] topic_name Name of the topic to subscribe to.
* \param[in] subscription_options options for the subscription.
* \param[in] is_serialized is true if the message will be delivered still serialized
*/
RCLCPP_PUBLIC
SubscriptionBase(
std::shared_ptr<rcl_node_t> node_handle,
const rosidl_message_type_support_t & type_support_handle,
const std::string & topic_name,
const rcl_subscription_options_t & subscription_options,
bool is_serialized = false);
/// Default destructor.
RCLCPP_PUBLIC
virtual ~SubscriptionBase();
/// Get the topic that this subscription is subscribed on.
RCLCPP_PUBLIC
const char *
get_topic_name() const;
RCLCPP_PUBLIC
std::shared_ptr<rcl_subscription_t>
get_subscription_handle();
RCLCPP_PUBLIC
const std::shared_ptr<rcl_subscription_t>
get_subscription_handle() const;
RCLCPP_PUBLIC
virtual const std::shared_ptr<rcl_subscription_t>
get_intra_process_subscription_handle() const;
/// Borrow a new message.
/** \return Shared pointer to the fresh message. */
virtual std::shared_ptr<void>
create_message() = 0;
/// Borrow a new serialized message
/** \return Shared pointer to a rcl_message_serialized_t. */
virtual std::shared_ptr<rcl_serialized_message_t>
create_serialized_message() = 0;
/// Check if we need to handle the message, and execute the callback if we do.
/**
* \param[in] message Shared pointer to the message to handle.
* \param[in] message_info Metadata associated with this message.
*/
virtual void
handle_message(std::shared_ptr<void> & message, const rmw_message_info_t & message_info) = 0;
/// Return the message borrowed in create_message.
/** \param[in] message Shared pointer to the returned message. */
virtual void
return_message(std::shared_ptr<void> & message) = 0;
/// Return the message borrowed in create_serialized_message.
/** \param[in] message Shared pointer to the returned message. */
virtual void
return_serialized_message(std::shared_ptr<rcl_serialized_message_t> & message) = 0;
virtual void
handle_intra_process_message(
rcl_interfaces::msg::IntraProcessMessage & ipm,
const rmw_message_info_t & message_info) = 0;
const rosidl_message_type_support_t &
get_message_type_support_handle() const;
bool
is_serialized() const;
protected:
std::shared_ptr<rcl_subscription_t> intra_process_subscription_handle_;
std::shared_ptr<rcl_subscription_t> subscription_handle_;
std::shared_ptr<rcl_node_t> node_handle_;
private:
RCLCPP_DISABLE_COPY(SubscriptionBase)
rosidl_message_type_support_t type_support_;
bool is_serialized_;
};
/// Subscription implementation, templated on the type of message this subscription receives.
template<
typename CallbackMessageT,
@@ -64,7 +153,6 @@ public:
using MessageAllocTraits = allocator::AllocRebind<CallbackMessageT, Alloc>;
using MessageAlloc = typename MessageAllocTraits::allocator_type;
using MessageDeleter = allocator::Deleter<MessageAlloc, CallbackMessageT>;
using ConstMessageSharedPtr = std::shared_ptr<const CallbackMessageT>;
using MessageUniquePtr = std::unique_ptr<CallbackMessageT, MessageDeleter>;
RCLCPP_SMART_PTR_DEFINITIONS(Subscription)
@@ -86,7 +174,6 @@ public:
const std::string & topic_name,
const rcl_subscription_options_t & subscription_options,
AnySubscriptionCallback<CallbackMessageT, Alloc> callback,
const SubscriptionEventCallbacks & event_callbacks,
typename message_memory_strategy::MessageMemoryStrategy<CallbackMessageT, Alloc>::SharedPtr
memory_strategy = message_memory_strategy::MessageMemoryStrategy<CallbackMessageT,
Alloc>::create_default())
@@ -97,17 +184,10 @@ public:
subscription_options,
rclcpp::subscription_traits::is_serialized_subscription_argument<CallbackMessageT>::value),
any_callback_(callback),
message_memory_strategy_(memory_strategy)
{
if (event_callbacks.deadline_callback) {
this->add_event_handler(event_callbacks.deadline_callback,
RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED);
}
if (event_callbacks.liveliness_callback) {
this->add_event_handler(event_callbacks.liveliness_callback,
RCL_SUBSCRIPTION_LIVELINESS_CHANGED);
}
}
message_memory_strategy_(memory_strategy),
get_intra_process_message_callback_(nullptr),
matches_any_intra_process_publishers_(nullptr)
{}
/// Support dynamically setting the message memory strategy.
/**
@@ -137,10 +217,12 @@ public:
void handle_message(std::shared_ptr<void> & message, const rmw_message_info_t & message_info)
{
if (matches_any_intra_process_publishers(&message_info.publisher_gid)) {
// In this case, the message will be delivered via intra process and
// we should ignore this copy of the message.
return;
if (matches_any_intra_process_publishers_) {
if (matches_any_intra_process_publishers_(&message_info.publisher_gid)) {
// In this case, the message will be delivered via intra process and
// we should ignore this copy of the message.
return;
}
}
auto typed_message = std::static_pointer_cast<CallbackMessageT>(message);
any_callback_.dispatch(typed_message, message_info);
@@ -163,109 +245,85 @@ public:
rcl_interfaces::msg::IntraProcessMessage & ipm,
const rmw_message_info_t & message_info)
{
if (!use_intra_process_) {
if (!get_intra_process_message_callback_) {
// throw std::runtime_error(
// "handle_intra_process_message called before setup_intra_process");
// TODO(wjwwood): for now, this could mean that intra process was just not enabled.
// However, this can only really happen if this node has it disabled, but the other doesn't.
return;
}
if (any_callback_.use_take_shared_method()) {
ConstMessageSharedPtr msg;
take_intra_process_message(
ipm.publisher_id,
ipm.message_sequence,
intra_process_subscription_id_,
msg);
if (!msg) {
// This either occurred because the publisher no longer exists or the
// message requested is no longer being stored.
RCLCPP_WARN(get_logger("rclcpp"),
"Intra process message not longer being stored when trying to handle it");
return;
}
any_callback_.dispatch_intra_process(msg, message_info);
} else {
MessageUniquePtr msg;
take_intra_process_message(
ipm.publisher_id,
ipm.message_sequence,
intra_process_subscription_id_,
msg);
if (!msg) {
// This either occurred because the publisher no longer exists or the
// message requested is no longer being stored.
RCLCPP_WARN(get_logger("rclcpp"),
"Intra process message not longer being stored when trying to handle it");
return;
}
any_callback_.dispatch_intra_process(std::move(msg), message_info);
MessageUniquePtr msg;
get_intra_process_message_callback_(
ipm.publisher_id,
ipm.message_sequence,
intra_process_subscription_id_,
msg);
if (!msg) {
// This either occurred because the publisher no longer exists or the
// message requested is no longer being stored.
// TODO(wjwwood): should we notify someone of this? log error, log warning?
return;
}
any_callback_.dispatch_intra_process(msg, message_info);
}
using GetMessageCallbackType =
std::function<void (uint64_t, uint64_t, uint64_t, MessageUniquePtr &)>;
using MatchesAnyPublishersCallbackType = std::function<bool (const rmw_gid_t *)>;
/// Implemenation detail.
void setup_intra_process(
uint64_t intra_process_subscription_id,
GetMessageCallbackType get_message_callback,
MatchesAnyPublishersCallbackType matches_any_publisher_callback,
const rcl_subscription_options_t & intra_process_options)
{
std::string intra_process_topic_name = std::string(get_topic_name()) + "/_intra";
rcl_ret_t ret = rcl_subscription_init(
intra_process_subscription_handle_.get(),
node_handle_.get(),
rclcpp::type_support::get_intra_process_message_msg_type_support(),
intra_process_topic_name.c_str(),
&intra_process_options);
if (ret != RCL_RET_OK) {
if (ret == RCL_RET_TOPIC_NAME_INVALID) {
auto rcl_node_handle = node_handle_.get();
// this will throw on any validation problem
rcl_reset_error();
expand_topic_or_service_name(
intra_process_topic_name,
rcl_node_get_name(rcl_node_handle),
rcl_node_get_namespace(rcl_node_handle));
}
rclcpp::exceptions::throw_from_rcl_error(ret, "could not create intra process subscription");
}
intra_process_subscription_id_ = intra_process_subscription_id;
get_intra_process_message_callback_ = get_message_callback;
matches_any_intra_process_publishers_ = matches_any_publisher_callback;
}
/// Implemenation detail.
const std::shared_ptr<rcl_subscription_t>
get_intra_process_subscription_handle() const
{
if (!use_intra_process_) {
if (!get_intra_process_message_callback_) {
return nullptr;
}
return intra_process_subscription_handle_;
}
private:
void
take_intra_process_message(
uint64_t publisher_id,
uint64_t message_sequence,
uint64_t subscription_id,
MessageUniquePtr & message)
{
auto ipm = weak_ipm_.lock();
if (!ipm) {
throw std::runtime_error(
"intra process take called after destruction of intra process manager");
}
ipm->template take_intra_process_message<CallbackMessageT, Alloc>(
publisher_id, message_sequence, subscription_id, message);
}
void
take_intra_process_message(
uint64_t publisher_id,
uint64_t message_sequence,
uint64_t subscription_id,
ConstMessageSharedPtr & message)
{
auto ipm = weak_ipm_.lock();
if (!ipm) {
throw std::runtime_error(
"intra process take called after destruction of intra process manager");
}
ipm->template take_intra_process_message<CallbackMessageT, Alloc>(
publisher_id, message_sequence, subscription_id, message);
}
bool
matches_any_intra_process_publishers(const rmw_gid_t * sender_gid)
{
if (!use_intra_process_) {
return false;
}
auto ipm = weak_ipm_.lock();
if (!ipm) {
throw std::runtime_error(
"intra process publisher check called "
"after destruction of intra process manager");
}
return ipm->matches_any_publishers(sender_gid);
}
RCLCPP_DISABLE_COPY(Subscription)
AnySubscriptionCallback<CallbackMessageT, Alloc> any_callback_;
typename message_memory_strategy::MessageMemoryStrategy<CallbackMessageT, Alloc>::SharedPtr
message_memory_strategy_;
GetMessageCallbackType get_intra_process_message_callback_;
MatchesAnyPublishersCallbackType matches_any_intra_process_publishers_;
uint64_t intra_process_subscription_id_;
};
} // namespace rclcpp

View File

@@ -1,189 +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__SUBSCRIPTION_BASE_HPP_
#define RCLCPP__SUBSCRIPTION_BASE_HPP_
#include <memory>
#include <string>
#include <vector>
#include "rcl/subscription.h"
#include "rcl_interfaces/msg/intra_process_message.hpp"
#include "rmw/rmw.h"
#include "rclcpp/any_subscription_callback.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace node_interfaces
{
class NodeTopicsInterface;
} // namespace node_interfaces
namespace intra_process_manager
{
/**
* IntraProcessManager is forward declared here, avoiding a circular inclusion between
* `intra_process_manager.hpp` and `subscription_base.hpp`.
*/
class IntraProcessManager;
}
/// Virtual base class for subscriptions. This pattern allows us to iterate over different template
/// specializations of Subscription, among other things.
class SubscriptionBase
{
public:
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(SubscriptionBase)
/// Default constructor.
/**
* \param[in] node_handle The rcl representation of the node that owns this subscription.
* \param[in] type_support_handle rosidl type support struct, for the Message type of the topic.
* \param[in] topic_name Name of the topic to subscribe to.
* \param[in] subscription_options options for the subscription.
* \param[in] is_serialized is true if the message will be delivered still serialized
*/
RCLCPP_PUBLIC
SubscriptionBase(
std::shared_ptr<rcl_node_t> node_handle,
const rosidl_message_type_support_t & type_support_handle,
const std::string & topic_name,
const rcl_subscription_options_t & subscription_options,
bool is_serialized = false);
/// Default destructor.
RCLCPP_PUBLIC
virtual ~SubscriptionBase();
/// Get the topic that this subscription is subscribed on.
RCLCPP_PUBLIC
const char *
get_topic_name() const;
RCLCPP_PUBLIC
std::shared_ptr<rcl_subscription_t>
get_subscription_handle();
RCLCPP_PUBLIC
const std::shared_ptr<rcl_subscription_t>
get_subscription_handle() const;
RCLCPP_PUBLIC
virtual const std::shared_ptr<rcl_subscription_t>
get_intra_process_subscription_handle() const;
/// Get all the QoS event handlers associated with this subscription.
/** \return The vector of QoS event handlers. */
RCLCPP_PUBLIC
const std::vector<std::shared_ptr<rclcpp::QOSEventHandlerBase>> &
get_event_handlers() const;
/// Borrow a new message.
/** \return Shared pointer to the fresh message. */
virtual std::shared_ptr<void>
create_message() = 0;
/// Borrow a new serialized message
/** \return Shared pointer to a rcl_message_serialized_t. */
virtual std::shared_ptr<rcl_serialized_message_t>
create_serialized_message() = 0;
/// Check if we need to handle the message, and execute the callback if we do.
/**
* \param[in] message Shared pointer to the message to handle.
* \param[in] message_info Metadata associated with this message.
*/
virtual void
handle_message(std::shared_ptr<void> & message, const rmw_message_info_t & message_info) = 0;
/// Return the message borrowed in create_message.
/** \param[in] message Shared pointer to the returned message. */
virtual void
return_message(std::shared_ptr<void> & message) = 0;
/// Return the message borrowed in create_serialized_message.
/** \param[in] message Shared pointer to the returned message. */
virtual void
return_serialized_message(std::shared_ptr<rcl_serialized_message_t> & message) = 0;
virtual void
handle_intra_process_message(
rcl_interfaces::msg::IntraProcessMessage & ipm,
const rmw_message_info_t & message_info) = 0;
const rosidl_message_type_support_t &
get_message_type_support_handle() const;
bool
is_serialized() const;
/// Get matching publisher count.
/** \return The number of publishers on this topic. */
RCLCPP_PUBLIC
size_t
get_publisher_count() const;
using IntraProcessManagerWeakPtr =
std::weak_ptr<rclcpp::intra_process_manager::IntraProcessManager>;
/// Implemenation detail.
void setup_intra_process(
uint64_t intra_process_subscription_id,
IntraProcessManagerWeakPtr weak_ipm,
const rcl_subscription_options_t & intra_process_options);
protected:
template<typename EventCallbackT>
void
add_event_handler(
const EventCallbackT & callback,
const rcl_subscription_event_type_t event_type)
{
auto handler = std::make_shared<QOSEventHandler<EventCallbackT>>(
callback,
rcl_subscription_event_init,
get_subscription_handle().get(),
event_type);
event_handlers_.emplace_back(handler);
}
std::shared_ptr<rcl_node_t> node_handle_;
std::shared_ptr<rcl_subscription_t> subscription_handle_;
std::shared_ptr<rcl_subscription_t> intra_process_subscription_handle_;
std::vector<std::shared_ptr<rclcpp::QOSEventHandlerBase>> event_handlers_;
bool use_intra_process_;
IntraProcessManagerWeakPtr weak_ipm_;
uint64_t intra_process_subscription_id_;
private:
RCLCPP_DISABLE_COPY(SubscriptionBase)
rosidl_message_type_support_t type_support_;
bool is_serialized_;
};
} // namespace rclcpp
#endif // RCLCPP__SUBSCRIPTION_BASE_HPP_

View File

@@ -51,7 +51,7 @@ struct SubscriptionFactory
rclcpp::SubscriptionBase::SharedPtr(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const std::string & topic_name,
const rcl_subscription_options_t & subscription_options)>;
rcl_subscription_options_t & subscription_options)>;
SubscriptionFactoryFunction create_typed_subscription;
@@ -75,7 +75,6 @@ template<
SubscriptionFactory
create_subscription_factory(
CallbackT && callback,
const SubscriptionEventCallbacks & event_callbacks,
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
CallbackMessageT, Alloc>::SharedPtr
msg_mem_strat,
@@ -92,14 +91,13 @@ create_subscription_factory(
// factory function that creates a MessageT specific SubscriptionT
factory.create_typed_subscription =
[allocator, msg_mem_strat, any_subscription_callback, event_callbacks, message_alloc](
[allocator, msg_mem_strat, any_subscription_callback, message_alloc](
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const std::string & topic_name,
const rcl_subscription_options_t & subscription_options
rcl_subscription_options_t & subscription_options
) -> rclcpp::SubscriptionBase::SharedPtr
{
auto options_copy = subscription_options;
options_copy.allocator =
subscription_options.allocator =
rclcpp::allocator::get_rcl_allocator<CallbackMessageT>(*message_alloc.get());
using rclcpp::Subscription;
@@ -109,14 +107,70 @@ create_subscription_factory(
node_base->get_shared_rcl_node_handle(),
*rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>(),
topic_name,
options_copy,
subscription_options,
any_subscription_callback,
event_callbacks,
msg_mem_strat);
auto sub_base_ptr = std::dynamic_pointer_cast<SubscriptionBase>(sub);
return sub_base_ptr;
};
// function that will setup intra process communications for the subscription
factory.setup_intra_process =
[message_alloc](
rclcpp::intra_process_manager::IntraProcessManager::SharedPtr ipm,
rclcpp::SubscriptionBase::SharedPtr subscription,
const rcl_subscription_options_t & subscription_options)
{
rclcpp::intra_process_manager::IntraProcessManager::WeakPtr weak_ipm = ipm;
uint64_t intra_process_subscription_id = ipm->add_subscription(subscription);
auto intra_process_options = rcl_subscription_get_default_options();
intra_process_options.allocator = rclcpp::allocator::get_rcl_allocator<CallbackMessageT>(
*message_alloc.get());
intra_process_options.qos = subscription_options.qos;
intra_process_options.ignore_local_publications = false;
// function that will be called to take a MessageT from the intra process manager
auto take_intra_process_message_func =
[weak_ipm](
uint64_t publisher_id,
uint64_t message_sequence,
uint64_t subscription_id,
typename rclcpp::Subscription<CallbackMessageT, Alloc>::MessageUniquePtr & message)
{
auto ipm = weak_ipm.lock();
if (!ipm) {
// TODO(wjwwood): should this just return silently? Or return with a logged warning?
throw std::runtime_error(
"intra process take called after destruction of intra process manager");
}
ipm->take_intra_process_message<CallbackMessageT, Alloc>(
publisher_id, message_sequence, subscription_id, message);
};
// function that is called to see if the publisher id matches any local publishers
auto matches_any_publisher_func =
[weak_ipm](const rmw_gid_t * sender_gid) -> bool
{
auto ipm = weak_ipm.lock();
if (!ipm) {
throw std::runtime_error(
"intra process publisher check called "
"after destruction of intra process manager");
}
return ipm->matches_any_publishers(sender_gid);
};
auto typed_sub_ptr = std::dynamic_pointer_cast<SubscriptionT>(subscription);
typed_sub_ptr->setup_intra_process(
intra_process_subscription_id,
take_intra_process_message_func,
matches_any_publisher_func,
intra_process_options
);
};
// end definition of factory function to setup intra process
// return the factory now that it is populated
return factory;
}

View File

@@ -1,79 +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__SUBSCRIPTION_OPTIONS_HPP_
#define RCLCPP__SUBSCRIPTION_OPTIONS_HPP_
#include <memory>
#include <string>
#include <vector>
#include "rclcpp/callback_group.hpp"
#include "rclcpp/intra_process_setting.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
/// Non-template base class for subscription options.
struct SubscriptionOptionsBase
{
/// Callbacks for events related to this subscription.
SubscriptionEventCallbacks event_callbacks;
/// True to ignore local publications.
bool ignore_local_publications = false;
/// The callback group for this subscription. NULL to use the default callback group.
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group = nullptr;
/// Setting to explicitly set intraprocess communications.
IntraProcessSetting use_intra_process_comm = IntraProcessSetting::NodeDefault;
};
/// Structure containing optional configuration for Subscriptions.
template<typename Allocator>
struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
{
/// Optional custom allocator.
std::shared_ptr<Allocator> allocator = nullptr;
SubscriptionOptionsWithAllocator<Allocator>() {}
/// Constructor using base class as input.
explicit SubscriptionOptionsWithAllocator(
const SubscriptionOptionsBase & subscription_options_base)
: SubscriptionOptionsBase(subscription_options_base)
{}
/// Convert this class, with a rclcpp::QoS, into an rcl_subscription_options_t.
template<typename MessageT>
rcl_subscription_options_t
to_rcl_subscription_options(const rclcpp::QoS & qos) const
{
rcl_subscription_options_t result;
using AllocatorTraits = std::allocator_traits<Allocator>;
using MessageAllocatorT = typename AllocatorTraits::template rebind_alloc<MessageT>;
auto message_alloc = std::make_shared<MessageAllocatorT>(*allocator.get());
result.allocator = allocator::get_rcl_allocator<MessageT>(*message_alloc);
result.ignore_local_publications = this->ignore_local_publications;
result.qos = qos.get_rmw_qos_profile();
return result;
}
};
using SubscriptionOptions = SubscriptionOptionsWithAllocator<std::allocator<void>>;
} // namespace rclcpp
#endif // RCLCPP__SUBSCRIPTION_OPTIONS_HPP_

View File

@@ -18,13 +18,9 @@
#include <memory>
#include "rclcpp/function_traits.hpp"
#include "rcl/types.h"
namespace rclcpp
{
class QoS;
namespace subscription_traits
{
@@ -73,20 +69,7 @@ template<typename MessageT, typename Deleter>
struct extract_message_type<std::unique_ptr<MessageT, Deleter>>: extract_message_type<MessageT>
{};
template<
typename CallbackT,
// Do not attempt if CallbackT is an integer (mistaken for depth)
typename = std::enable_if_t<!std::is_integral<
std::remove_cv_t<std::remove_reference_t<CallbackT>>>::value>,
// Do not attempt if CallbackT is a QoS (mistaken for qos)
typename = std::enable_if_t<!std::is_base_of<
rclcpp::QoS,
std::remove_cv_t<std::remove_reference_t<CallbackT>>>::value>,
// Do not attempt if CallbackT is a rmw_qos_profile_t (mistaken for qos profile)
typename = std::enable_if_t<!std::is_same<
rmw_qos_profile_t,
std::remove_cv_t<std::remove_reference_t<CallbackT>>>::value>
>
template<typename CallbackT>
struct has_message_type : extract_message_type<
typename rclcpp::function_traits::function_traits<CallbackT>::template argument_type<0>>
{};

View File

@@ -58,16 +58,6 @@ public:
void
cancel();
/// Return the timer cancellation state.
/**
* \return true if the timer has been cancelled, false otherwise
* \throws std::runtime_error if the rcl_get_error_state returns 0
* \throws RCLErrorBase some child class exception based on ret
*/
RCLCPP_PUBLIC
bool
is_canceled();
RCLCPP_PUBLIC
void
reset();

View File

@@ -0,0 +1,115 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__UNUSED_PARAMETERS_CHECKER_HPP_
#define RCLCPP__UNUSED_PARAMETERS_CHECKER_HPP_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "rclcpp/node_interfaces/get_node_parameters_interface.hpp"
#include "rclcpp/node_interfaces/node_parameters_interface.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
/// Check a Node-like class for unused parameters.
/**
* This class can be used to detect misconfigurations and typos by ensuring all
* initial parameter values that were passed to the Node-like object were used.
* So this class's methods are used after or during Node construction and after
* all parameters have been declared.
*
* This class must not outlive the Node that it's being used with.
*/
class UnusedParametersChecker
{
public:
template<typename NodeType>
explicit UnusedParametersChecker(NodeType && node_like)
: node_parameters_interface_(
rclcpp::node_interfaces::get_node_parameters_interface(std::forward<NodeType>(node_like)))
{}
/// Warn if any initial parameter values have not been used.
/**
* This function will complain with a RCLCPP_WARN if any provided initial
* parameter values have not been used.
*
* \throws std::bad_alloc when trying to create an error message
*/
RCLCPP_PUBLIC
void
check_and_warn() const;
/// Throw an UnusedParameterExecption if any initial parameter values have not been used.
/**
* This function will throw an exception if any provided initial
* parameter values have not been used.
*
* \throws std::bad_alloc when trying to create an error message
* \throws rclcpp::UnusedParametersException when there are unused parameters
*/
RCLCPP_PUBLIC
void
check_and_throw() const;
/// Return the number of unused initial parameter values.
/**
* Similar to get_unused_initial_parameter_values(), but it returns the
* number of unused parameter values rather than a vector of the unused
* parameters (which involves allocating storage for the copies).
* This function is faster and avoids memory allocation while checking for a
* problem, and if one is detected then get_unused_initial_parameter_values()
* may be used to format a useful error message.
*
* \returns the number of unused initial parameter values
*/
RCLCPP_PUBLIC
size_t
count_unused_initial_parameter_values() const;
/// Return the list of unused initial parameter values.
/**
* A common case where this returns a non-empty vector, is when someone makes
* a typo when setting the parameters from outside the node.
* For example, if they use `ip_addr` rather than the expected `ip_address`.
*
* \returns vector of parameters which where passed to the node but where
* not declared before this function was called.
* \throws std::bad_alloc
*/
RCLCPP_PUBLIC
std::vector<rclcpp::Parameter>
get_unused_initial_parameter_values() const;
private:
const rclcpp::node_interfaces::NodeParametersInterface * node_parameters_interface_;
};
/// Thrown when throw_if_unused_initialized_parameter_values() finds unused parameters.
class UnusedParametersException : public std::runtime_error
{
public:
explicit UnusedParametersException(const std::vector<rclcpp::Parameter> & unused_parameters);
};
} // namespace rclcpp
#endif // RCLCPP__UNUSED_PARAMETERS_CHECKER_HPP_

View File

@@ -18,14 +18,17 @@
#include <chrono>
#include <functional>
#include <limits>
#include <string>
#include <vector>
#include "rclcpp/context.hpp"
#include "rclcpp/init_options.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rmw/macros.h"
#include "rmw/rmw.h"
#ifdef ANDROID
#include <string>
#include <sstream>
namespace std
@@ -101,7 +104,6 @@ uninstall_signal_handlers();
*
* \sa rclcpp::Context::init() for more details on arguments and possible exceptions
* \returns Members of the argument vector that are not ROS arguments.
* \throws anything remove_ros_arguments can throw
*/
RCLCPP_PUBLIC
std::vector<std::string>
@@ -120,8 +122,6 @@ init_and_remove_ros_arguments(
* \param[in] argc Number of arguments.
* \param[in] argv Argument vector.
* \returns Members of the argument vector that are not ROS arguments.
* \throws anything throw_from_rcl_error can throw
* \throws rclcpp::exceptions::RCLErrorBase if the parsing fails
*/
RCLCPP_PUBLIC
std::vector<std::string>

View File

@@ -61,17 +61,6 @@ public:
size_t
get_number_of_ready_clients();
/// Get the number of ready events
/**
* Returns a value of 0 by default.
* This should be overridden if the Waitable contains one or more events.
* \return The number of events associated with the Waitable.
*/
RCLCPP_PUBLIC
virtual
size_t
get_number_of_ready_events();
/// Get the number of ready services
/**
* Returns a value of 0 by default.
@@ -99,7 +88,6 @@ public:
/**
* \param[in] wait_set A handle to the wait set to add the Waitable to.
* \return `true` if the Waitable is added successfully, `false` otherwise.
* \throws rclcpp::execptions::RCLError from rcl_wait_set_add_*()
*/
RCLCPP_PUBLIC
virtual

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp</name>
<version>0.7.2</version>
<version>0.6.2</version>
<description>The ROS client library in C++.</description>
<maintainer email="dthomas@osrfoundation.org">Dirk Thomas</maintainer>
<license>Apache License 2.0</license>

View File

@@ -1,4 +1,4 @@
# Copyright 2019 Open Source Robotics Foundation, Inc.
# 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.
@@ -12,18 +12,18 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# copied from rclcpp_components/rclcpp_components-extras.cmake
# copied from rclcpp/rclcpp-extras.cmake
# register ament_package() hook for node plugins once.
macro(_rclcpp_components_register_package_hook)
if(NOT DEFINED _RCLCPP_COMPONENTS_PACKAGE_HOOK_REGISTERED)
set(_RCLCPP_COMPONENTS_PACKAGE_HOOK_REGISTERED TRUE)
# register ament_package() hook for node plugins once
macro(_rclcpp_register_package_hook)
if(NOT DEFINED _RCLCPP_PACKAGE_HOOK_REGISTERED)
set(_RCLCPP_PACKAGE_HOOK_REGISTERED TRUE)
find_package(ament_cmake_core QUIET REQUIRED)
ament_register_extension("ament_package" "rclcpp_components"
"rclcpp_components_package_hook.cmake")
ament_register_extension("ament_package" "rclcpp"
"rclcpp_package_hook.cmake")
endif()
endmacro()
include("${rclcpp_components_DIR}/rclcpp_components_register_nodes.cmake")
include("${rclcpp_DIR}/rclcpp_create_node_main.cmake")
include("${rclcpp_DIR}/rclcpp_register_node_plugins.cmake")

View File

@@ -1,77 +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__NODE_INTERFACES__INTERFACE_TRAITS_HPP_
#define RCLCPP__NODE_INTERFACES__INTERFACE_TRAITS_HPP_
#include <functional>
#include <type_traits>
@{
node_interfaces = [
'node_base_interface',
'node_clock_interface',
'node_graph_interface',
'node_logging_interface',
'node_parameters_interface',
'node_services_interface',
'node_time_source_interface',
'node_timers_interface',
'node_topics_interface',
'node_waitables_interface',
]
node_interface_types = [
'NodeBaseInterface',
'NodeClockInterface',
'NodeGraphInterface',
'NodeLoggingInterface',
'NodeParametersInterface',
'NodeServicesInterface',
'NodeTimeSourceInterface',
'NodeTimersInterface',
'NodeTopicsInterface',
'NodeWaitablesInterface',
]
assert (len(node_interfaces) == len(node_interface_types))
}@
@[for interface_ in node_interfaces]@
#include "rclcpp/node_interfaces/@(interface_).hpp"
@[end for]@
namespace rclcpp
{
namespace node_interfaces
{
@[for (interface_, type_) in zip(node_interfaces, node_interface_types)]@
using @(interface_)_getter_t = std::shared_ptr<rclcpp::node_interfaces::@(type_)>;
template<class T, typename = void>
struct has_@(interface_) : std::false_type
{};
template<class T>
struct has_@(interface_)<
T, typename std::enable_if<
std::is_same<
@(interface_)_getter_t, decltype(std::declval<T>().get_@(interface_)())>::value>::type> : std::true_type
{};
@[end for]@
} // namespace node_interfaces
} // namespace rclcpp
#endif // RCLCPP__NODE_INTERFACES__INTERFACE_TRAITS_HPP_

View File

@@ -71,9 +71,6 @@ def is_supported_feature_combination(feature_combination):
#else
@[ for feature_combination in [fc for fc in feature_combinations if is_supported_feature_combination(fc)]]@
@{suffix = get_suffix_from_features(feature_combination)}@
// The RCLCPP_@(severity)@(suffix) macro is surrounded by do { .. } while (0)
// to implement the standard C macro idiom to make the macro safe in all
// contexts; see http://c-faq.com/cpp/multistmt.html for more information.
/**
* \def RCLCPP_@(severity)@(suffix)
* Log a message with severity @(severity)@
@@ -93,20 +90,18 @@ def is_supported_feature_combination(feature_combination):
* It also accepts a single argument of type std::string.
*/
#define RCLCPP_@(severity)@(suffix)(logger, @(''.join([p + ', ' for p in get_macro_parameters(feature_combination).keys()]))...) \
do { \
static_assert( \
::std::is_same<typename std::remove_reference<typename std::remove_cv<decltype(logger)>::type>::type, \
typename ::rclcpp::Logger>::value, \
"First argument to logging macros must be an rclcpp::Logger"); \
RCUTILS_LOG_@(severity)@(suffix)_NAMED( \
static_assert( \
::std::is_same<typename std::remove_reference<decltype(logger)>::type, \
typename ::rclcpp::Logger>::value, \
"First argument to logging macros must be an rclcpp::Logger"); \
RCUTILS_LOG_@(severity)@(suffix)_NAMED( \
@{params = get_macro_parameters(feature_combination).keys()}@
@[ if params]@
@(''.join([' ' + p + ', \\\n' for p in params]))@
@(''.join([' ' + p + ', \\\n' for p in params]))@
@[ end if]@
logger.get_name(), \
rclcpp::get_c_string(RCLCPP_FIRST_ARG(__VA_ARGS__, "")), \
RCLCPP_ALL_BUT_FIRST_ARGS(__VA_ARGS__,"")); \
} while (0)
logger.get_name(), \
rclcpp::get_c_string(RCLCPP_FIRST_ARG(__VA_ARGS__, "")), \
RCLCPP_ALL_BUT_FIRST_ARGS(__VA_ARGS__,""))
@[ end for]@
#endif

View File

@@ -118,6 +118,7 @@ ClientBase::wait_for_service_nanoseconds(std::chrono::nanoseconds timeout)
if (!node_ptr) {
throw InvalidNodeError();
}
auto event = node_ptr->get_graph_event();
// check to see if the server is ready immediately
if (this->service_is_ready()) {
return true;
@@ -126,7 +127,6 @@ ClientBase::wait_for_service_nanoseconds(std::chrono::nanoseconds timeout)
// check was non-blocking, return immediately
return false;
}
auto event = node_ptr->get_graph_event();
// update the time even on the first loop to account for time spent in the first call
// to this->server_is_ready()
std::chrono::nanoseconds time_to_wait =

View File

@@ -14,6 +14,14 @@
#include "rclcpp/clock.hpp"
#include <memory>
#include <utility>
#include <vector>
#include "builtin_interfaces/msg/time.hpp"
#include "rcl/time.h"
#include "rclcpp/exceptions.hpp"
#include "rcutils/logging_macros.h"
@@ -22,8 +30,8 @@ namespace rclcpp
{
JumpHandler::JumpHandler(
pre_callback_t pre_callback,
post_callback_t post_callback,
std::function<void()> pre_callback,
std::function<void(const rcl_time_jump_t &)> post_callback,
const rcl_jump_threshold_t & threshold)
: pre_callback(pre_callback),
post_callback(post_callback),
@@ -35,7 +43,8 @@ Clock::Clock(rcl_clock_type_t clock_type)
allocator_ = rcl_get_default_allocator();
auto ret = rcl_clock_init(clock_type, &rcl_clock_, &allocator_);
if (ret != RCL_RET_OK) {
exceptions::throw_from_rcl_error(ret, "could not get current time stamp");
rclcpp::exceptions::throw_from_rcl_error(
ret, "could not get current time stamp");
}
}
@@ -54,7 +63,8 @@ Clock::now()
auto ret = rcl_clock_get_now(&rcl_clock_, &now.rcl_time_.nanoseconds);
if (ret != RCL_RET_OK) {
exceptions::throw_from_rcl_error(ret, "could not get current time stamp");
rclcpp::exceptions::throw_from_rcl_error(
ret, "could not get current time stamp");
}
return now;
@@ -68,23 +78,23 @@ Clock::ros_time_is_active()
return false;
}
bool is_enabled = false;
bool is_enabled;
auto ret = rcl_is_enabled_ros_time_override(&rcl_clock_, &is_enabled);
if (ret != RCL_RET_OK) {
exceptions::throw_from_rcl_error(
rclcpp::exceptions::throw_from_rcl_error(
ret, "Failed to check ros_time_override_status");
}
return is_enabled;
}
rcl_clock_t *
Clock::get_clock_handle() noexcept
Clock::get_clock_handle()
{
return &rcl_clock_;
}
rcl_clock_type_t
Clock::get_clock_type() const noexcept
Clock::get_clock_type()
{
return rcl_clock_.type;
}
@@ -95,10 +105,7 @@ Clock::on_time_jump(
bool before_jump,
void * user_data)
{
const auto * handler = static_cast<JumpHandler *>(user_data);
if (nullptr == handler) {
return;
}
rclcpp::JumpHandler * handler = static_cast<rclcpp::JumpHandler *>(user_data);
if (before_jump && handler->pre_callback) {
handler->pre_callback();
} else if (!before_jump && handler->post_callback) {
@@ -106,30 +113,31 @@ Clock::on_time_jump(
}
}
JumpHandler::SharedPtr
rclcpp::JumpHandler::SharedPtr
Clock::create_jump_callback(
JumpHandler::pre_callback_t pre_callback,
JumpHandler::post_callback_t post_callback,
std::function<void()> pre_callback,
std::function<void(const rcl_time_jump_t &)> post_callback,
const rcl_jump_threshold_t & threshold)
{
// Allocate a new jump handler
JumpHandler::UniquePtr handler(new JumpHandler(pre_callback, post_callback, threshold));
auto handler = new rclcpp::JumpHandler(pre_callback, post_callback, threshold);
if (nullptr == handler) {
throw std::bad_alloc{};
rclcpp::exceptions::throw_from_rcl_error(RCL_RET_BAD_ALLOC, "Failed to allocate jump handler");
}
// Try to add the jump callback to the clock
rcl_ret_t ret = rcl_clock_add_jump_callback(&rcl_clock_, threshold,
Clock::on_time_jump, handler.get());
rclcpp::Clock::on_time_jump, handler);
if (RCL_RET_OK != ret) {
exceptions::throw_from_rcl_error(ret, "Failed to add time jump callback");
delete handler;
handler = NULL;
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to add time jump callback");
}
// *INDENT-OFF*
// create shared_ptr that removes the callback automatically when all copies are destructed
// TODO(dorezyuk) UB, if the clock leaves scope before the JumpHandler
return JumpHandler::SharedPtr(handler.release(), [this](JumpHandler * handler) noexcept {
rcl_ret_t ret = rcl_clock_remove_jump_callback(&rcl_clock_, Clock::on_time_jump,
return rclcpp::JumpHandler::SharedPtr(handler, [this](rclcpp::JumpHandler * handler) noexcept {
rcl_ret_t ret = rcl_clock_remove_jump_callback(&rcl_clock_, rclcpp::Clock::on_time_jump,
handler);
delete handler;
handler = NULL;

View File

@@ -65,6 +65,10 @@ Duration::Duration(const rcl_duration_t & duration)
// noop
}
Duration::~Duration()
{
}
Duration::operator builtin_interfaces::msg::Duration() const
{
builtin_interfaces::msg::Duration msg_duration;
@@ -222,15 +226,4 @@ Duration::seconds() const
return std::chrono::duration<double>(std::chrono::nanoseconds(rcl_duration_.nanoseconds)).count();
}
rmw_time_t
Duration::to_rmw_time() const
{
// reuse conversion logic from msg creation
builtin_interfaces::msg::Duration msg = *this;
rmw_time_t result;
result.sec = msg.sec;
result.nsec = msg.nanosec;
return result;
}
} // namespace rclcpp

View File

@@ -39,8 +39,8 @@ NameValidationError::format_error(
return msg;
}
std::exception_ptr
from_rcl_error(
void
throw_from_rcl_error(
rcl_ret_t ret,
const std::string & prefix,
const rcl_error_state_t * error_state,
@@ -55,9 +55,9 @@ from_rcl_error(
if (!error_state) {
throw std::runtime_error("rcl error state is not set");
}
std::string formatted_prefix = prefix;
std::string formated_prefix = prefix;
if (!prefix.empty()) {
formatted_prefix += ": ";
formated_prefix += ": ";
}
RCLErrorBase base_exc(ret, error_state);
if (reset_error) {
@@ -65,28 +65,14 @@ from_rcl_error(
}
switch (ret) {
case RCL_RET_BAD_ALLOC:
return std::make_exception_ptr(RCLBadAlloc(base_exc));
throw RCLBadAlloc(base_exc);
case RCL_RET_INVALID_ARGUMENT:
return std::make_exception_ptr(RCLInvalidArgument(base_exc, formatted_prefix));
throw RCLInvalidArgument(base_exc, formated_prefix);
default:
return std::make_exception_ptr(RCLError(base_exc, formatted_prefix));
throw RCLError(base_exc, formated_prefix);
}
}
void
throw_from_rcl_error(
rcl_ret_t ret,
const std::string & prefix,
const rcl_error_state_t * error_state,
void (* reset_error)())
{
// We expect this to either throw a standard error,
// or to generate an error pointer (which is caught
// in err, and immediately thrown)
auto err = from_rcl_error(ret, prefix, error_state, reset_error);
std::rethrow_exception(err);
}
RCLErrorBase::RCLErrorBase(rcl_ret_t ret, const rcl_error_state_t * error_state)
: ret(ret), message(error_state->message), file(error_state->file), line(error_state->line_number),
formatted_message(rcl_get_error_string().str)

View File

@@ -60,11 +60,7 @@ Executor::Executor(const ExecutorArgs & args)
// Store the context for later use.
context_ = args.context;
ret = rcl_wait_set_init(
&wait_set_,
0, 2, 0, 0, 0, 0,
context_->get_rcl_context().get(),
allocator);
ret = rcl_wait_set_init(&wait_set_, 0, 2, 0, 0, 0, context_->get_rcl_context().get(), allocator);
if (RCL_RET_OK != ret) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
@@ -308,7 +304,7 @@ Executor::execute_subscription(
auto serialized_msg = subscription->create_serialized_message();
auto ret = rcl_take_serialized_message(
subscription->get_subscription_handle().get(),
serialized_msg.get(), &message_info, nullptr);
serialized_msg.get(), &message_info);
if (RCL_RET_OK == ret) {
auto void_serialized_msg = std::static_pointer_cast<void>(serialized_msg);
subscription->handle_message(void_serialized_msg, message_info);
@@ -324,7 +320,7 @@ Executor::execute_subscription(
std::shared_ptr<void> message = subscription->create_message();
auto ret = rcl_take(
subscription->get_subscription_handle().get(),
message.get(), &message_info, nullptr);
message.get(), &message_info);
if (RCL_RET_OK == ret) {
subscription->handle_message(message, message_info);
} else if (RCL_RET_SUBSCRIPTION_TAKE_FAILED != ret) {
@@ -347,8 +343,7 @@ Executor::execute_intra_process_subscription(
rcl_ret_t status = rcl_take(
subscription->get_intra_process_subscription_handle().get(),
&ipm,
&message_info,
nullptr);
&message_info);
if (status == RCL_RET_OK) {
message_info.from_intra_process = true;
@@ -439,8 +434,7 @@ Executor::wait_for_work(std::chrono::nanoseconds timeout)
rcl_ret_t ret = rcl_wait_set_resize(
&wait_set_, memory_strategy_->number_of_ready_subscriptions(),
memory_strategy_->number_of_guard_conditions(), memory_strategy_->number_of_ready_timers(),
memory_strategy_->number_of_ready_clients(), memory_strategy_->number_of_ready_services(),
memory_strategy_->number_of_ready_events());
memory_strategy_->number_of_ready_clients(), memory_strategy_->number_of_ready_services());
if (RCL_RET_OK != ret) {
throw std::runtime_error(
std::string("Couldn't resize the wait set : ") + rcl_get_error_string().str);

View File

@@ -82,6 +82,7 @@ MultiThreadedExecutor::run(size_t)
}
if (any_exec.timer) {
// Guard against multiple threads getting the same timer.
std::lock_guard<std::mutex> lock(scheduled_timers_mutex_);
if (scheduled_timers_.count(any_exec.timer) != 0) {
continue;
}
@@ -95,14 +96,11 @@ MultiThreadedExecutor::run(size_t)
execute_any_executable(any_exec);
if (any_exec.timer) {
std::lock_guard<std::mutex> wait_lock(wait_mutex_);
std::lock_guard<std::mutex> lock(scheduled_timers_mutex_);
auto it = scheduled_timers_.find(any_exec.timer);
if (it != scheduled_timers_.end()) {
scheduled_timers_.erase(it);
}
}
// Clear the callback_group to prevent the AnyExecutable destructor from
// resetting the callback group `can_be_taken_from`
any_exec.callback_group.reset();
}
}

View File

@@ -79,7 +79,6 @@ GraphListener::start_if_not_started()
0, // number_of_timers
0, // number_of_clients
0, // number_of_services
0, // number_of_events
this->parent_context_->get_rcl_context().get(),
rcl_get_default_allocator());
if (RCL_RET_OK != ret) {
@@ -146,7 +145,7 @@ GraphListener::run_loop()
const size_t node_graph_interfaces_size = node_graph_interfaces_.size();
// Add 2 for the interrupt and shutdown guard conditions
if (wait_set_.size_of_guard_conditions < (node_graph_interfaces_size + 2)) {
ret = rcl_wait_set_resize(&wait_set_, 0, node_graph_interfaces_size + 2, 0, 0, 0, 0);
ret = rcl_wait_set_resize(&wait_set_, 0, node_graph_interfaces_size + 2, 0, 0, 0);
if (RCL_RET_OK != ret) {
throw_from_rcl_error(ret, "failed to resize wait set");
}

View File

@@ -29,21 +29,6 @@ IntraProcessManager::IntraProcessManager(
IntraProcessManager::~IntraProcessManager()
{}
uint64_t
IntraProcessManager::add_publisher(
rclcpp::PublisherBase::SharedPtr publisher,
size_t buffer_size)
{
auto id = IntraProcessManager::get_next_unique_id();
size_t size = buffer_size > 0 ? buffer_size : publisher->get_queue_size();
auto mrb = publisher->make_mapped_ring_buffer(size);
impl_->add_publisher(id, publisher, mrb, size);
if (!mrb) {
throw std::runtime_error("failed to create a mapped ring buffer");
}
return id;
}
uint64_t
IntraProcessManager::add_subscription(
rclcpp::SubscriptionBase::SharedPtr subscription)
@@ -71,12 +56,6 @@ IntraProcessManager::matches_any_publishers(const rmw_gid_t * id) const
return impl_->matches_any_publishers(id);
}
size_t
IntraProcessManager::get_subscription_count(uint64_t intra_process_publisher_id) const
{
return impl_->get_subscription_count(intra_process_publisher_id);
}
uint64_t
IntraProcessManager::get_next_unique_id()
{

View File

@@ -27,93 +27,43 @@
#include "rclcpp/node_interfaces/node_clock.hpp"
#include "rclcpp/node_interfaces/node_graph.hpp"
#include "rclcpp/node_interfaces/node_logging.hpp"
// When compiling this file, Windows produces a deprecation warning for the
// deprecated function prototype of NodeParameters::register_param_change_callback().
// Other compilers do not.
#if defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
#include "rclcpp/node_interfaces/node_parameters.hpp"
#if defined(_WIN32)
# pragma warning(pop)
#endif
#include "rclcpp/node_interfaces/node_services.hpp"
#include "rclcpp/node_interfaces/node_time_source.hpp"
#include "rclcpp/node_interfaces/node_timers.hpp"
#include "rclcpp/node_interfaces/node_topics.hpp"
#include "rclcpp/node_interfaces/node_waitables.hpp"
#include "rmw/validate_namespace.h"
using rclcpp::Node;
using rclcpp::NodeOptions;
using rclcpp::exceptions::throw_from_rcl_error;
RCLCPP_LOCAL
std::string
extend_sub_namespace(const std::string & existing_sub_namespace, const std::string & extension)
{
// Assumption is that the existing_sub_namespace does not need checking
// because it would be checked already when it was set with this function.
// check if the new sub-namespace extension is absolute
if (extension.front() == '/') {
throw rclcpp::exceptions::NameValidationError(
"sub_namespace",
extension.c_str(),
"a sub-namespace should not have a leading /",
0);
}
std::string new_sub_namespace;
if (existing_sub_namespace.empty()) {
new_sub_namespace = extension;
} else {
new_sub_namespace = existing_sub_namespace + "/" + extension;
}
// remove any trailing `/` so that new extensions do no result in `//`
if (new_sub_namespace.back() == '/') {
new_sub_namespace = new_sub_namespace.substr(0, new_sub_namespace.size() - 1);
}
return new_sub_namespace;
}
RCLCPP_LOCAL
std::string
create_effective_namespace(const std::string & node_namespace, const std::string & sub_namespace)
{
// Assumption is that both the node_namespace and sub_namespace are conforming
// and do not need trimming of `/` and other things, as they were validated
// in other functions already.
if (node_namespace.back() == '/') {
// this is the special case where node_namespace is just `/`
return node_namespace + sub_namespace;
} else {
return node_namespace + "/" + sub_namespace;
}
}
Node::Node(
const std::string & node_name,
const NodeOptions & options)
: Node(node_name, "", options)
{
}
Node::Node(
const std::string & node_name,
const std::string & namespace_,
const NodeOptions & options)
bool use_intra_process_comms)
: Node(
node_name,
namespace_,
rclcpp::contexts::default_context::get_global_default_context(),
{},
{},
true,
use_intra_process_comms,
true)
{}
Node::Node(
const std::string & node_name,
const std::string & namespace_,
rclcpp::Context::SharedPtr context,
const std::vector<std::string> & arguments,
const std::vector<rclcpp::Parameter> & initial_parameters,
bool use_global_arguments,
bool use_intra_process_comms,
bool start_parameter_services,
bool allow_undeclared_parameters)
: node_base_(new rclcpp::node_interfaces::NodeBase(
node_name,
namespace_,
options.context(),
*(options.get_rcl_node_options()),
options.use_intra_process_comms())),
node_name, namespace_, context, arguments, use_global_arguments)),
node_graph_(new rclcpp::node_interfaces::NodeGraph(node_base_.get())),
node_logging_(new rclcpp::node_interfaces::NodeLogging(node_base_.get())),
node_timers_(new rclcpp::node_interfaces::NodeTimers(node_base_.get())),
@@ -128,17 +78,13 @@ Node::Node(
)),
node_parameters_(new rclcpp::node_interfaces::NodeParameters(
node_base_,
node_logging_,
node_topics_,
node_services_,
node_clock_,
options.initial_parameters(),
options.start_parameter_services(),
options.start_parameter_event_publisher(),
options.parameter_event_qos(),
options.parameter_event_publisher_options(),
options.allow_undeclared_parameters(),
options.automatically_declare_initial_parameters()
initial_parameters,
use_intra_process_comms,
start_parameter_services,
allow_undeclared_parameters
)),
node_time_source_(new rclcpp::node_interfaces::NodeTimeSource(
node_base_,
@@ -150,48 +96,10 @@ Node::Node(
node_parameters_
)),
node_waitables_(new rclcpp::node_interfaces::NodeWaitables(node_base_.get())),
node_options_(options),
sub_namespace_(""),
effective_namespace_(create_effective_namespace(this->get_namespace(), sub_namespace_))
use_intra_process_comms_(use_intra_process_comms)
{
}
Node::Node(
const Node & other,
const std::string & sub_namespace)
: node_base_(other.node_base_),
node_graph_(other.node_graph_),
node_logging_(other.node_logging_),
node_timers_(other.node_timers_),
node_topics_(other.node_topics_),
node_services_(other.node_services_),
node_clock_(other.node_clock_),
node_parameters_(other.node_parameters_),
node_options_(other.node_options_),
sub_namespace_(extend_sub_namespace(other.get_sub_namespace(), sub_namespace)),
effective_namespace_(create_effective_namespace(other.get_namespace(), sub_namespace_))
{
// Validate new effective namespace.
int validation_result;
size_t invalid_index;
rmw_ret_t rmw_ret =
rmw_validate_namespace(effective_namespace_.c_str(), &validation_result, &invalid_index);
if (rmw_ret != RMW_RET_OK) {
if (rmw_ret == RMW_RET_INVALID_ARGUMENT) {
throw_from_rcl_error(RCL_RET_INVALID_ARGUMENT, "failed to validate subnode namespace");
}
throw_from_rcl_error(RCL_RET_ERROR, "failed to validate subnode namespace");
}
if (validation_result != RMW_NAMESPACE_VALID) {
throw rclcpp::exceptions::InvalidNamespaceError(
effective_namespace_.c_str(),
rmw_namespace_validation_result_string(validation_result),
invalid_index);
}
}
Node::~Node()
{}
@@ -207,12 +115,6 @@ Node::get_namespace() const
return node_base_->get_namespace();
}
const char *
Node::get_fully_qualified_name() const
{
return node_base_->get_fully_qualified_name();
}
rclcpp::Logger
Node::get_logger() const
{
@@ -232,57 +134,29 @@ Node::group_in_node(rclcpp::callback_group::CallbackGroup::SharedPtr group)
return node_base_->callback_group_in_node(group);
}
const rclcpp::ParameterValue &
void
Node::declare_parameter(
const std::string & name,
const rclcpp::ParameterValue & default_value,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor)
bool read_only)
{
return this->node_parameters_->declare_parameter(name, default_value, parameter_descriptor);
}
void
Node::undeclare_parameter(const std::string & name)
{
this->node_parameters_->undeclare_parameter(name);
}
bool
Node::has_parameter(const std::string & name) const
{
return this->node_parameters_->has_parameter(name);
}
rcl_interfaces::msg::SetParametersResult
Node::set_parameter(const rclcpp::Parameter & parameter)
{
return this->set_parameters_atomically({parameter});
return this->node_parameters_->declare_parameter(name, default_value, read_only);
}
std::vector<rcl_interfaces::msg::SetParametersResult>
Node::set_parameters(const std::vector<rclcpp::Parameter> & parameters)
Node::set_parameters(
const std::vector<rclcpp::Parameter> & parameters)
{
return node_parameters_->set_parameters(parameters);
}
rcl_interfaces::msg::SetParametersResult
Node::set_parameters_atomically(const std::vector<rclcpp::Parameter> & parameters)
Node::set_parameters_atomically(
const std::vector<rclcpp::Parameter> & parameters)
{
return node_parameters_->set_parameters_atomically(parameters);
}
rclcpp::Parameter
Node::get_parameter(const std::string & name) const
{
return node_parameters_->get_parameter(name);
}
bool
Node::get_parameter(const std::string & name, rclcpp::Parameter & parameter) const
{
return node_parameters_->get_parameter(name, parameter);
}
std::vector<rclcpp::Parameter>
Node::get_parameters(
const std::vector<std::string> & names) const
@@ -290,43 +164,40 @@ Node::get_parameters(
return node_parameters_->get_parameters(names);
}
rcl_interfaces::msg::ParameterDescriptor
Node::describe_parameter(const std::string & name) const
rclcpp::Parameter
Node::get_parameter(const std::string & name) const
{
auto result = node_parameters_->describe_parameters({name});
if (0 == result.size()) {
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
}
if (result.size() > 1) {
throw std::runtime_error("number of described parameters unexpectedly more than one");
}
return result.front();
return node_parameters_->get_parameter(name);
}
bool Node::get_parameter(
const std::string & name,
rclcpp::Parameter & parameter) const
{
return node_parameters_->get_parameter(name, parameter);
}
std::vector<rcl_interfaces::msg::ParameterDescriptor>
Node::describe_parameters(const std::vector<std::string> & names) const
Node::describe_parameters(
const std::vector<std::string> & names) const
{
return node_parameters_->describe_parameters(names);
}
std::vector<uint8_t>
Node::get_parameter_types(const std::vector<std::string> & names) const
Node::get_parameter_types(
const std::vector<std::string> & names) const
{
return node_parameters_->get_parameter_types(names);
}
rcl_interfaces::msg::ListParametersResult
Node::list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const
Node::list_parameters(
const std::vector<std::string> & prefixes, uint64_t depth) const
{
return node_parameters_->list_parameters(prefixes, depth);
}
rclcpp::Node::OnParametersSetCallbackType
Node::set_on_parameters_set_callback(rclcpp::Node::OnParametersSetCallbackType callback)
{
return node_parameters_->set_on_parameters_set_callback(callback);
}
std::vector<std::string>
Node::get_node_names() const
{
@@ -448,35 +319,3 @@ Node::get_node_waitables_interface()
{
return node_waitables_;
}
const std::string &
Node::get_sub_namespace() const
{
return this->sub_namespace_;
}
const std::string &
Node::get_effective_namespace() const
{
return this->effective_namespace_;
}
Node::SharedPtr
Node::create_sub_node(const std::string & sub_namespace)
{
// Cannot use make_shared<Node>() here as it requires the constructor to be
// public, and this constructor is intentionally protected instead.
return std::shared_ptr<Node>(new Node(*this, sub_namespace));
}
const NodeOptions &
Node::get_node_options() const
{
return this->node_options_;
}
bool
Node::assert_liveliness() const
{
return node_base_->assert_liveliness();
}

View File

@@ -33,10 +33,9 @@ NodeBase::NodeBase(
const std::string & node_name,
const std::string & namespace_,
rclcpp::Context::SharedPtr context,
const rcl_node_options_t & rcl_node_options,
bool use_intra_process_default)
const std::vector<std::string> & arguments,
bool use_global_arguments)
: context_(context),
use_intra_process_default_(use_intra_process_default),
node_handle_(nullptr),
default_callback_group_(nullptr),
associated_with_executor_(false),
@@ -45,7 +44,7 @@ NodeBase::NodeBase(
// Setup the guard condition that is notified when changes occur in the graph.
rcl_guard_condition_options_t guard_condition_options = rcl_guard_condition_get_default_options();
rcl_ret_t ret = rcl_guard_condition_init(
&notify_guard_condition_, context_->get_rcl_context().get(), guard_condition_options);
&notify_guard_condition_, context->get_rcl_context().get(), guard_condition_options);
if (ret != RCL_RET_OK) {
throw_from_rcl_error(ret, "failed to create interrupt guard condition");
}
@@ -60,16 +59,76 @@ NodeBase::NodeBase(
}
};
// Determine the domain id based on the options and the ROS_DOMAIN_ID env variable.
size_t domain_id = 0;
char * ros_domain_id = nullptr;
const char * env_var = "ROS_DOMAIN_ID";
#ifndef _WIN32
ros_domain_id = getenv(env_var);
#else
size_t ros_domain_id_size;
_dupenv_s(&ros_domain_id, &ros_domain_id_size, env_var);
#endif
if (ros_domain_id) {
uint32_t number = strtoul(ros_domain_id, NULL, 0);
if (number == (std::numeric_limits<uint32_t>::max)()) {
// Finalize the interrupt guard condition.
finalize_notify_guard_condition();
#ifdef _WIN32
// free the ros_domain_id before throwing, if getenv was used on Windows
free(ros_domain_id);
#endif
throw std::runtime_error("failed to interpret ROS_DOMAIN_ID as integral number");
}
domain_id = static_cast<size_t>(number);
#ifdef _WIN32
free(ros_domain_id);
#endif
}
// Create the rcl node and store it in a shared_ptr with a custom destructor.
std::unique_ptr<rcl_node_t> rcl_node(new rcl_node_t(rcl_get_zero_initialized_node()));
rcl_node_options_t options = rcl_node_get_default_options();
std::unique_ptr<const char *[]> c_args;
if (!arguments.empty()) {
c_args.reset(new const char *[arguments.size()]);
for (std::size_t i = 0; i < arguments.size(); ++i) {
c_args[i] = arguments[i].c_str();
}
}
// TODO(sloretz) Pass an allocator to argument parsing
if (arguments.size() > std::numeric_limits<int>::max()) {
throw_from_rcl_error(RCL_RET_INVALID_ARGUMENT, "Too many args");
}
ret = rcl_parse_arguments(
static_cast<int>(arguments.size()), c_args.get(), rcl_get_default_allocator(),
&(options.arguments));
if (RCL_RET_OK != ret) {
finalize_notify_guard_condition();
throw_from_rcl_error(ret, "failed to parse arguments");
}
options.use_global_arguments = use_global_arguments;
// TODO(wjwwood): pass the Allocator to the options
options.domain_id = domain_id;
ret = rcl_node_init(
rcl_node.get(),
node_name.c_str(), namespace_.c_str(),
context_->get_rcl_context().get(), &rcl_node_options);
context->get_rcl_context().get(), &options);
if (ret != RCL_RET_OK) {
// Finalize the interrupt guard condition.
finalize_notify_guard_condition();
// Finalize previously allocated node arguments
if (RCL_RET_OK != rcl_arguments_fini(&options.arguments)) {
// Print message because exception will be thrown later in this code block
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Failed to fini arguments during error handling: %s", rcl_get_error_string().str);
rcl_reset_error();
}
if (ret == RCL_RET_NODE_INVALID_NAME) {
rcl_reset_error(); // discard rcl_node_init error
@@ -136,6 +195,15 @@ NodeBase::NodeBase(
// Indicate the notify_guard_condition is now valid.
notify_guard_condition_is_valid_ = true;
// Finalize previously allocated node arguments
if (RCL_RET_OK != rcl_arguments_fini(&options.arguments)) {
// print message because throwing would prevent the destructor from being called
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Failed to fini arguments: %s", rcl_get_error_string().str);
rcl_reset_error();
}
}
NodeBase::~NodeBase()
@@ -164,12 +232,6 @@ NodeBase::get_namespace() const
return rcl_node_get_namespace(node_handle_.get());
}
const char *
NodeBase::get_fully_qualified_name() const
{
return rcl_node_get_fully_qualified_name(node_handle_.get());
}
rclcpp::Context::SharedPtr
NodeBase::get_context()
{
@@ -200,12 +262,6 @@ NodeBase::get_shared_rcl_node_handle() const
return node_handle_;
}
bool
NodeBase::assert_liveliness() const
{
return RCL_RET_OK == rcl_node_assert_liveliness(get_rcl_node_handle());
}
rclcpp::callback_group::CallbackGroup::SharedPtr
NodeBase::create_callback_group(rclcpp::callback_group::CallbackGroupType group_type)
{
@@ -262,9 +318,3 @@ NodeBase::acquire_notify_guard_condition_lock() const
{
return std::unique_lock<std::recursive_mutex>(notify_guard_condition_mutex_);
}
bool
NodeBase::get_use_intra_process_default() const
{
return use_intra_process_default_;
}

View File

@@ -14,7 +14,6 @@
#include "rclcpp/node_interfaces/node_graph.hpp"
#include <algorithm>
#include <map>
#include <string>
#include <utility>
@@ -137,24 +136,9 @@ NodeGraph::get_node_names() const
std::vector<std::string> nodes;
auto names_and_namespaces = get_node_names_and_namespaces();
std::transform(names_and_namespaces.begin(),
names_and_namespaces.end(),
std::back_inserter(nodes),
[](std::pair<std::string, std::string> nns) {
std::string return_string;
if (nns.second.back() == '/') {
return_string = nns.second + nns.first;
} else {
return_string = nns.second + '/' + nns.first;
}
// Quick check to make sure that we start with a slash
// Since fully-qualified strings need to
if (return_string.front() != '/') {
return_string = "/" + return_string;
}
return return_string;
}
);
for (const auto & it : names_and_namespaces) {
nodes.push_back(it.first);
}
return nodes;
}
@@ -189,12 +173,10 @@ NodeGraph::get_node_names_and_namespaces() const
throw std::runtime_error(error_msg);
}
std::vector<std::pair<std::string, std::string>> node_names;
node_names.reserve(node_names_c.size);
std::vector<std::pair<std::string, std::string>> node_names(node_names_c.size);
for (size_t i = 0; i < node_names_c.size; ++i) {
if (node_names_c.data[i] && node_namespaces_c.data[i]) {
node_names.emplace_back(node_names_c.data[i], node_namespaces_c.data[i]);
node_names.push_back(std::make_pair(node_names_c.data[i], node_namespaces_c.data[i]));
}
}

View File

@@ -12,17 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// When compiling this file, Windows produces a deprecation warning for the
// deprecated function prototype of NodeParameters::register_param_change_callback().
// Other compilers do not.
#if defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
#include "rclcpp/node_interfaces/node_parameters.hpp"
#if defined(_WIN32)
# pragma warning(pop)
#endif
#include <rcl_yaml_param_parser/parser.h>
@@ -44,41 +34,31 @@ using rclcpp::node_interfaces::NodeParameters;
NodeParameters::NodeParameters(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
const rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
const rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services,
const rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock,
const std::vector<rclcpp::Parameter> & initial_parameters,
bool use_intra_process,
bool start_parameter_services,
bool start_parameter_event_publisher,
const rclcpp::QoS & parameter_event_qos,
const rclcpp::PublisherOptionsBase & parameter_event_publisher_options,
bool allow_undeclared_parameters,
bool automatically_declare_initial_parameters)
: allow_undeclared_(allow_undeclared_parameters),
events_publisher_(nullptr),
node_logging_(node_logging),
node_clock_(node_clock)
bool allow_undeclared_parameters)
: allow_undeclared_(allow_undeclared_parameters), node_clock_(node_clock)
{
using MessageT = rcl_interfaces::msg::ParameterEvent;
using PublisherT = rclcpp::Publisher<MessageT>;
using AllocatorT = std::allocator<void>;
// TODO(wjwwood): expose this allocator through the Parameter interface.
rclcpp::PublisherOptionsWithAllocator<AllocatorT> publisher_options(
parameter_event_publisher_options);
publisher_options.allocator = std::make_shared<AllocatorT>();
auto allocator = std::make_shared<AllocatorT>();
if (start_parameter_services) {
parameter_service_ = std::make_shared<ParameterService>(node_base, node_services, this);
}
if (start_parameter_event_publisher) {
events_publisher_ = rclcpp::create_publisher<MessageT, AllocatorT, PublisherT>(
node_topics,
"parameter_events",
parameter_event_qos,
publisher_options);
}
events_publisher_ = rclcpp::create_publisher<MessageT, AllocatorT, PublisherT>(
node_topics.get(),
"parameter_events",
rmw_qos_profile_parameter_events,
use_intra_process,
allocator);
// Get the node options
const rcl_node_t * node = node_base->get_rcl_node_handle();
@@ -122,7 +102,18 @@ NodeParameters::NodeParameters(
get_yaml_paths(&(options->arguments));
// Get fully qualified node name post-remapping to use to find node's params in yaml files
combined_name_ = node_base->get_fully_qualified_name();
const std::string node_name = node_base->get_name();
const std::string node_namespace = node_base->get_namespace();
if (0u == node_namespace.size() || 0u == node_name.size()) {
// Should never happen
throw std::runtime_error("Node name and namespace were not set");
}
if ('/' == node_namespace.at(node_namespace.size() - 1)) {
combined_name_ = node_namespace + node_name;
} else {
combined_name_ = node_namespace + '/' + node_name;
}
// TODO(sloretz) use rcl to parse yaml when circular dependency is solved
// See https://github.com/ros2/rcl/issues/252
@@ -159,16 +150,10 @@ NodeParameters::NodeParameters(
rclcpp::ParameterValue(param.get_value_message());
}
// If asked, initialize any parameters that ended up in the initial parameter values,
// but did not get declared explcitily by this point.
if (automatically_declare_initial_parameters) {
for (const auto & pair : this->get_initial_parameter_values()) {
if (!this->has_parameter(pair.first)) {
this->declare_parameter(
pair.first,
pair.second,
rcl_interfaces::msg::ParameterDescriptor());
}
if (!initial_parameters.empty() && allow_undeclared_) {
rcl_interfaces::msg::SetParametersResult result = set_parameters_atomically(initial_parameters);
if (!result.successful) {
throw std::runtime_error("Failed to set initial parameters");
}
}
}
@@ -176,354 +161,171 @@ NodeParameters::NodeParameters(
NodeParameters::~NodeParameters()
{}
RCLCPP_LOCAL
bool
__lockless_has_parameter(
const std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameters,
const std::string & name)
{
return parameters.find(name) != parameters.end();
}
using OnParametersSetCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::OnParametersSetCallbackType;
RCLCPP_LOCAL
rcl_interfaces::msg::SetParametersResult
__set_parameters_atomically_common(
const std::vector<rclcpp::Parameter> & parameters,
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameter_infos,
OnParametersSetCallbackType on_set_parameters_callback)
{
// Call the user callback to see if the new value(s) are allowed.
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
if (on_set_parameters_callback) {
result = on_set_parameters_callback(parameters);
}
// If accepted, actually set the values.
if (result.successful) {
for (size_t i = 0; i < parameters.size(); ++i) {
const std::string & name = parameters[i].get_name();
parameter_infos[name].descriptor.name = parameters[i].get_name();
parameter_infos[name].descriptor.type = parameters[i].get_type();
parameter_infos[name].value = parameters[i].get_parameter_value();
}
}
// Either way, return the result.
return result;
}
RCLCPP_LOCAL
rcl_interfaces::msg::SetParametersResult
__declare_parameter_common(
const std::string & name,
const rclcpp::ParameterValue & default_value,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameters_out,
const std::map<std::string, rclcpp::ParameterValue> & initial_values,
OnParametersSetCallbackType on_set_parameters_callback,
rcl_interfaces::msg::ParameterEvent * parameter_event_out)
{
using rclcpp::node_interfaces::ParameterInfo;
std::map<std::string, ParameterInfo> parameter_infos {{name, ParameterInfo()}};
parameter_infos.at(name).descriptor = parameter_descriptor;
// Use the value from the initial_values if available, otherwise use the default.
const rclcpp::ParameterValue * initial_value = &default_value;
auto initial_value_it = initial_values.find(name);
if (initial_value_it != initial_values.end()) {
initial_value = &initial_value_it->second;
}
// Check with the user's callback to see if the initial value can be set.
std::vector<rclcpp::Parameter> parameter_wrappers {rclcpp::Parameter(name, *initial_value)};
// This function also takes care of default vs initial value.
auto result = __set_parameters_atomically_common(
parameter_wrappers,
parameter_infos,
on_set_parameters_callback);
// Add declared parameters to storage.
parameters_out[name] = parameter_infos.at(name);
// Extend the given parameter event, if valid.
if (parameter_event_out) {
parameter_event_out->new_parameters.push_back(parameter_wrappers[0].to_parameter_msg());
}
return result;
}
const rclcpp::ParameterValue &
void
NodeParameters::declare_parameter(
const std::string & name,
const rclcpp::ParameterValue & default_value,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor)
bool read_only)
{
std::lock_guard<std::mutex> lock(mutex_);
// TODO(sloretz) parameter name validation
if (name.empty()) {
throw rclcpp::exceptions::InvalidParametersException("parameter name must not be empty");
throw std::runtime_error("parameter name must not be empty");
}
// Error if this parameter has already been declared and is different
if (__lockless_has_parameter(parameters_, name)) {
throw rclcpp::exceptions::ParameterAlreadyDeclaredException(
"parameter '" + name + "' has already been declared");
auto param_iter = parameters_.find(name);
if (param_iter != parameters_.end() && param_iter->second.is_declared) {
if (
param_iter->second.descriptor.type != default_value.get_type() ||
param_iter->second.descriptor.read_only != read_only)
{
throw std::runtime_error("parameter '" + name + "' exists with conflicting description");
}
}
rcl_interfaces::msg::ParameterEvent parameter_event;
auto result = __declare_parameter_common(
name,
default_value,
parameter_descriptor,
parameters_,
initial_parameter_values_,
on_parameters_set_callback_,
&parameter_event);
// If it failed to be set, then throw an exception.
if (!result.successful) {
throw rclcpp::exceptions::InvalidParameterValueException(
"parameter '" + name + "' could not be set: " + result.reason);
// Check if run-time user passed an initial value, else use the default.
rclcpp::ParameterValue initial_value = default_value;
auto value_iter = initial_parameter_values_.find(name);
if (value_iter != initial_parameter_values_.end()) {
initial_value = value_iter->second;
}
// Publish if events_publisher_ is not nullptr, which may be if disabled in the constructor.
if (nullptr != events_publisher_) {
// Save a description of the parameter
rcl_interfaces::msg::ParameterDescriptor desc;
desc.name = name;
desc.type = initial_value.get_type();
desc.read_only = read_only;
rclcpp::node_interfaces::ParameterInfo pinfo;
pinfo.is_declared = true;
pinfo.value = initial_value;
pinfo.descriptor = desc;
// Add declared parameters to storage, even when they're not set.
parameters_[name] = pinfo;
// If it has an actual value then add it to 'new_parameters' event
if (rclcpp::ParameterType::PARAMETER_NOT_SET != initial_value.get_type()) {
auto parameter_event = std::make_shared<rcl_interfaces::msg::ParameterEvent>();
parameter_event->new_parameters.push_back(
rclcpp::Parameter(name, initial_value).to_parameter_msg());
events_publisher_->publish(parameter_event);
}
return parameters_.at(name).value;
}
void
NodeParameters::undeclare_parameter(const std::string & name)
{
std::lock_guard<std::mutex> lock(mutex_);
auto parameter_info = parameters_.find(name);
if (parameter_info == parameters_.end()) {
throw rclcpp::exceptions::ParameterNotDeclaredException(
"cannot undeclare parameter '" + name + "' which has not yet been declared");
}
if (parameter_info->second.descriptor.read_only) {
throw rclcpp::exceptions::ParameterImmutableException(
"cannot undeclare parameter '" + name + "' because it is read-only");
}
parameters_.erase(parameter_info);
}
bool
NodeParameters::has_parameter(const std::string & name) const
{
std::lock_guard<std::mutex> lock(mutex_);
return __lockless_has_parameter(parameters_, name);
}
std::vector<rcl_interfaces::msg::SetParametersResult>
NodeParameters::set_parameters(const std::vector<rclcpp::Parameter> & parameters)
NodeParameters::set_parameters(
const std::vector<rclcpp::Parameter> & parameters)
{
std::vector<rcl_interfaces::msg::SetParametersResult> results;
results.reserve(parameters.size());
for (const auto & p : parameters) {
for (auto p : parameters) {
auto result = set_parameters_atomically({{p}});
results.push_back(result);
}
return results;
}
template<typename ParameterVectorType>
auto
__find_parameter_by_name(
ParameterVectorType & parameters,
const std::string & name)
{
return std::find_if(
parameters.begin(),
parameters.end(),
[&](auto parameter) {return parameter.get_name() == name;});
}
rcl_interfaces::msg::SetParametersResult
NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> & parameters)
NodeParameters::set_parameters_atomically(
const std::vector<rclcpp::Parameter> & parameters)
{
std::lock_guard<std::mutex> lock(mutex_);
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> tmp_map;
auto parameter_event = std::make_shared<rcl_interfaces::msg::ParameterEvent>();
parameter_event->node = combined_name_;
// TODO(jacquelinekay): handle parameter constraints
rcl_interfaces::msg::SetParametersResult result;
// Check if any of the parameters are read-only, or if any parameters are not
// declared.
// If not declared, keep track of them in order to declare them later, when
// undeclared parameters are allowed, and if they're not allowed, fail.
std::vector<const rclcpp::Parameter *> parameters_to_be_declared;
for (const auto & parameter : parameters) {
const std::string & name = parameter.get_name();
// Check to make sure the parameter name is valid.
if (name.empty()) {
throw rclcpp::exceptions::InvalidParametersException("parameter name must not be empty");
}
// Check to see if it is declared.
auto parameter_info = parameters_.find(name);
if (parameter_info == parameters_.end()) {
// If not check to see if undeclared paramaters are allowed, ...
if (allow_undeclared_) {
// If so, mark the parameter to be declared for the user implicitly.
parameters_to_be_declared.push_back(&parameter);
// continue as it cannot be read-only, and because the declare will
// implicitly set the parameter and parameter_infos is for setting only.
continue;
} else {
// If not, then throw the exception as documented.
throw rclcpp::exceptions::ParameterNotDeclaredException(
"parameter '" + name + "' cannot be set because it was not declared");
}
}
// Check to see if it is read-only.
if (parameter_info->second.descriptor.read_only) {
result.successful = false;
result.reason = "parameter '" + name + "' cannot be set because it is read-only";
return result;
}
if (parameters_callback_) {
result = parameters_callback_(parameters);
} else {
result.successful = true;
}
// Declare parameters into a temporary "staging area", incase one of the declares fail.
// We will use the staged changes as input to the "set atomically" action.
// We explicitly avoid calling the user callback here, so that it may be called once, with
// all the other parameters to be set (already declared parameters).
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> staged_parameter_changes;
rcl_interfaces::msg::ParameterEvent parameter_event_msg;
parameter_event_msg.node = combined_name_;
for (auto parameter_to_be_declared : parameters_to_be_declared) {
// This should not throw, because we validated the name and checked that
// the parameter was not already declared.
result = __declare_parameter_common(
parameter_to_be_declared->get_name(),
parameter_to_be_declared->get_parameter_value(),
rcl_interfaces::msg::ParameterDescriptor(), // Implicit declare uses default descriptor.
staged_parameter_changes,
initial_parameter_values_,
nullptr, // callback is explicitly null, so that it is called only once, when setting below.
&parameter_event_msg);
if (!result.successful) {
// Declare failed, return knowing that nothing was changed because the
// staged changes were not applied.
return result;
}
}
// If there were implicitly declared parameters, then we may need to copy the input parameters
// and then assign the value that was selected after the declare (could be affected by the
// initial parameter values).
const std::vector<rclcpp::Parameter> * parameters_to_be_set = &parameters;
std::vector<rclcpp::Parameter> parameters_copy;
if (0 != staged_parameter_changes.size()) { // If there were any implicitly declared parameters.
bool any_initial_values_used = false;
for (const auto & staged_parameter_change : staged_parameter_changes) {
auto it = __find_parameter_by_name(parameters, staged_parameter_change.first);
if (it->get_parameter_value() != staged_parameter_change.second.value) {
// In this case, the value of the staged parameter differs from the
// input from the user, and therefore we need to update things before setting.
any_initial_values_used = true;
// No need to search further since at least one initial value needs to be used.
break;
}
}
if (any_initial_values_used) {
parameters_copy = parameters;
for (const auto & staged_parameter_change : staged_parameter_changes) {
auto it = __find_parameter_by_name(parameters_copy, staged_parameter_change.first);
*it = Parameter(staged_parameter_change.first, staged_parameter_change.second.value);
}
parameters_to_be_set = &parameters_copy;
}
}
// Collect parameters who will have had their type changed to
// rclcpp::PARAMETER_NOT_SET so they can later be implicitly undeclared.
std::vector<const rclcpp::Parameter *> parameters_to_be_undeclared;
for (const auto & parameter : *parameters_to_be_set) {
if (rclcpp::PARAMETER_NOT_SET == parameter.get_type()) {
auto it = parameters_.find(parameter.get_name());
if (it != parameters_.end() && rclcpp::PARAMETER_NOT_SET != it->second.value.get_type()) {
parameters_to_be_undeclared.push_back(&parameter);
}
}
}
// Set the all of the parameters including the ones declared implicitly above.
result = __set_parameters_atomically_common(
// either the original parameters given by the user, or ones updated with initial values
*parameters_to_be_set,
// they are actually set on the official parameter storage
parameters_,
// this will get called once, with all the parameters to be set
on_parameters_set_callback_);
// If not successful, then stop here.
if (!result.successful) {
return result;
}
// If successful, then update the parameter infos from the implicitly declared parameter's.
for (const auto & kv_pair : staged_parameter_changes) {
// assumption: the parameter is already present in parameters_ due to the above "set"
assert(__lockless_has_parameter(parameters_, kv_pair.first));
// assumption: the value in parameters_ is the same as the value resulting from the declare
assert(parameters_[kv_pair.first].value == kv_pair.second.value);
// This assignment should not change the name, type, or value, but may
// change other things from the ParameterInfo.
parameters_[kv_pair.first] = kv_pair.second;
}
std::vector<std::string> to_delete;
// Undeclare parameters that need to be.
for (auto parameter_to_undeclare : parameters_to_be_undeclared) {
auto it = parameters_.find(parameter_to_undeclare->get_name());
// assumption: the parameter to be undeclared should be in the parameter infos map
assert(it != parameters_.end());
if (it != parameters_.end()) {
// Remove it and update the parameter event message.
parameters_.erase(it);
parameter_event_msg.deleted_parameters.push_back(
rclcpp::Parameter(it->first, it->second.value).to_parameter_msg());
for (auto p : parameters) {
auto param_iter = parameters_.find(p.get_name());
bool exists = parameters_.end() != param_iter;
bool want_to_delete = p.get_type() == rclcpp::ParameterType::PARAMETER_NOT_SET;
if (exists) {
if (param_iter->second.descriptor.read_only) {
result.successful = false;
result.reason = "read_only parameter: '" + p.get_name() + "'";
return result;
}
if (want_to_delete) {
parameter_event->deleted_parameters.push_back(p.to_parameter_msg());
if (param_iter->second.is_declared) {
// clear declared parameter value, but don't delete it
rclcpp::node_interfaces::ParameterInfo cleared_param_info = param_iter->second;
cleared_param_info.value = rclcpp::ParameterValue();
tmp_map[p.get_name()] = cleared_param_info;
} else {
// Truly delete an undeclared parameter
to_delete.push_back(p.get_name());
}
} else {
if (param_iter->second.value.get_type() == rclcpp::ParameterType::PARAMETER_NOT_SET) {
// case: setting a value on a declared parameter that currently is unset
parameter_event->new_parameters.push_back(p.to_parameter_msg());
} else {
// case: changing a parameter value
parameter_event->changed_parameters.push_back(p.to_parameter_msg());
}
rclcpp::node_interfaces::ParameterInfo changed_param_info = param_iter->second;
// TODO(sloretz) Add accessor for ParameterValue on Parameter class
changed_param_info.value = rclcpp::ParameterValue(p.get_value_message());
tmp_map[p.get_name()] = changed_param_info;
}
} else {
// case: parameter does not exist already
if (!allow_undeclared_) {
result.successful = false;
result.reason = "undeclared parameter: '" + p.get_name() + "'";
return result;
} else if (want_to_delete) {
result.successful = false;
result.reason = "deleting parameter: '" + p.get_name() + "' that does not exist";
return result;
} else {
// Create new undeclared parameter
parameter_event->new_parameters.push_back(p.to_parameter_msg());
rcl_interfaces::msg::ParameterDescriptor desc;
desc.name = p.get_name();
desc.type = p.get_type();
desc.read_only = false;
rclcpp::node_interfaces::ParameterInfo new_param_info;
new_param_info.is_declared = false;
// TODO(sloretz) Add accessor for ParameterValue on Parameter class
new_param_info.value = rclcpp::ParameterValue(p.get_value_message());
new_param_info.descriptor = desc;
tmp_map[p.get_name()] = new_param_info;
}
}
}
// std::map::insert will not overwrite elements, so we'll keep the new
// ones and add only those that already exist in the Node's internal map
tmp_map.insert(parameters_.begin(), parameters_.end());
// Update the parameter event message for any parameters which were only set,
// and not either declared or undeclared.
for (const auto & parameter : *parameters_to_be_set) {
if (staged_parameter_changes.find(parameter.get_name()) != staged_parameter_changes.end()) {
// This parameter was declared.
continue;
}
auto it = std::find_if(
parameters_to_be_undeclared.begin(),
parameters_to_be_undeclared.end(),
[&parameter](const auto & p) {return p->get_name() == parameter.get_name();});
if (it != parameters_to_be_undeclared.end()) {
// This parameter was undeclared (deleted).
continue;
}
// This parameter was neither declared nor undeclared.
parameter_event_msg.changed_parameters.push_back(parameter.to_parameter_msg());
// remove truly deleted parameters
for (const std::string & param_name : to_delete) {
tmp_map.erase(param_name);
}
// Publish if events_publisher_ is not nullptr, which may be if disabled in the constructor.
if (nullptr != events_publisher_) {
parameter_event_msg.stamp = node_clock_->get_clock()->now();
events_publisher_->publish(parameter_event_msg);
}
std::swap(tmp_map, parameters_);
parameter_event->stamp = node_clock_->get_clock()->now();
events_publisher_->publish(parameter_event);
return result;
}
@@ -533,19 +335,14 @@ NodeParameters::get_parameters(const std::vector<std::string> & names) const
{
std::lock_guard<std::mutex> lock(mutex_);
std::vector<rclcpp::Parameter> results;
results.reserve(names.size());
for (auto & name : names) {
auto found_parameter = parameters_.find(name);
if (found_parameter != parameters_.cend()) {
// found
results.emplace_back(name, found_parameter->second.value);
} else if (this->allow_undeclared_) {
// not found, but undeclared allowed
results.emplace_back(name, rclcpp::ParameterValue());
} else {
// not found, and undeclared are not allowed
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
if (std::any_of(parameters_.cbegin(), parameters_.cend(),
[&name](const std::pair<std::string, rclcpp::node_interfaces::ParameterInfo> & kv) {
return name == kv.first;
}))
{
results.emplace_back(name, parameters_.at(name).value);
}
}
return results;
@@ -558,10 +355,8 @@ NodeParameters::get_parameter(const std::string & name) const
if (get_parameter(name, parameter)) {
return parameter;
} else if (this->allow_undeclared_) {
return parameter;
} else {
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
throw std::out_of_range("Parameter '" + name + "' not set");
}
}
@@ -589,11 +384,11 @@ NodeParameters::get_parameters_by_prefix(
const std::string & prefix,
std::map<std::string, rclcpp::Parameter> & parameters) const
{
std::lock_guard<std::mutex> lock(mutex_);
std::string prefix_with_dot = prefix.empty() ? prefix : prefix + ".";
std::string prefix_with_dot = prefix + ".";
bool ret = false;
std::lock_guard<std::mutex> lock(mutex_);
for (const auto & param : parameters_) {
if (param.first.find(prefix_with_dot) == 0 && param.first.length() > prefix_with_dot.length()) {
// Found one!
@@ -610,26 +405,14 @@ NodeParameters::describe_parameters(const std::vector<std::string> & names) cons
{
std::lock_guard<std::mutex> lock(mutex_);
std::vector<rcl_interfaces::msg::ParameterDescriptor> results;
results.reserve(names.size());
for (const auto & name : names) {
auto it = parameters_.find(name);
if (it != parameters_.cend()) {
results.push_back(it->second.descriptor);
} else if (allow_undeclared_) {
// parameter not found, but undeclared allowed, so return empty
rcl_interfaces::msg::ParameterDescriptor default_description;
default_description.name = name;
results.push_back(default_description);
} else {
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
for (auto & kv : parameters_) {
if (std::any_of(names.cbegin(), names.cend(), [&kv](const std::string & name) {
return name == kv.first;
}))
{
results.push_back(kv.second.descriptor);
}
}
if (results.size() != names.size()) {
throw std::runtime_error("results and names unexpectedly different sizes");
}
return results;
}
@@ -638,24 +421,16 @@ NodeParameters::get_parameter_types(const std::vector<std::string> & names) cons
{
std::lock_guard<std::mutex> lock(mutex_);
std::vector<uint8_t> results;
results.reserve(names.size());
for (const auto & name : names) {
auto it = parameters_.find(name);
if (it != parameters_.cend()) {
results.push_back(it->second.value.get_type());
} else if (allow_undeclared_) {
// parameter not found, but undeclared allowed, so return not set
results.push_back(rcl_interfaces::msg::ParameterType::PARAMETER_NOT_SET);
for (auto & kv : parameters_) {
if (std::any_of(names.cbegin(), names.cend(), [&kv](const std::string & name) {
return name == kv.first;
}))
{
results.push_back(kv.second.value.get_type());
} else {
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
results.push_back(rcl_interfaces::msg::ParameterType::PARAMETER_NOT_SET);
}
}
if (results.size() != names.size()) {
throw std::runtime_error("results and names unexpectedly different sizes");
}
return results;
}
@@ -701,39 +476,12 @@ NodeParameters::list_parameters(const std::vector<std::string> & prefixes, uint6
return result;
}
NodeParameters::OnParametersSetCallbackType
NodeParameters::set_on_parameters_set_callback(OnParametersSetCallbackType callback)
{
auto existing_callback = on_parameters_set_callback_;
on_parameters_set_callback_ = callback;
return existing_callback;
}
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
void
NodeParameters::register_param_change_callback(ParametersCallbackFunction callback)
{
if (on_parameters_set_callback_) {
RCLCPP_WARN(
node_logging_->get_logger(),
"on_parameters_set_callback already registered, overwriting previous callback");
if (parameters_callback_) {
RCUTILS_LOG_WARN("param_change_callback already registered, "
"overwriting previous callback");
}
on_parameters_set_callback_ = callback;
}
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
const std::map<std::string, rclcpp::ParameterValue> &
NodeParameters::get_initial_parameter_values() const
{
return initial_parameter_values_;
parameters_callback_ = callback;
}

View File

@@ -34,7 +34,7 @@ rclcpp::PublisherBase::SharedPtr
NodeTopics::create_publisher(
const std::string & topic_name,
const rclcpp::PublisherFactory & publisher_factory,
const rcl_publisher_options_t & publisher_options,
rcl_publisher_options_t & publisher_options,
bool use_intra_process)
{
// Create the MessageT specific Publisher using the factory, but store it as PublisherBase.
@@ -47,10 +47,13 @@ NodeTopics::create_publisher(
// Get the intra process manager instance for this context.
auto ipm = context->get_sub_context<rclcpp::intra_process_manager::IntraProcessManager>();
// Register the publisher with the intra process manager.
uint64_t intra_process_publisher_id = ipm->add_publisher(publisher);
uint64_t intra_process_publisher_id =
publisher_factory.add_publisher_to_intra_process_manager(ipm.get(), publisher);
// Create a function to be called when publisher to do the intra process publish.
auto shared_publish_callback = publisher_factory.create_shared_publish_callback(ipm);
publisher->setup_intra_process(
intra_process_publisher_id,
ipm,
shared_publish_callback,
publisher_options);
}
@@ -60,22 +63,11 @@ NodeTopics::create_publisher(
void
NodeTopics::add_publisher(
rclcpp::PublisherBase::SharedPtr publisher,
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group)
rclcpp::PublisherBase::SharedPtr publisher)
{
// Assign to a group.
if (callback_group) {
if (!node_base_->callback_group_in_node(callback_group)) {
throw std::runtime_error("Cannot create publisher, callback group not in node.");
}
} else {
callback_group = node_base_->get_default_callback_group();
}
for (auto & publisher_event : publisher->get_event_handlers()) {
callback_group->add_waitable(publisher_event);
}
// The publisher is not added to a callback group or anthing like that for now.
// It may be stored within the NodeTopics class or the NodeBase class in the future.
(void)publisher;
// Notify the executor that a new publisher was created using the parent Node.
{
auto notify_guard_condition_lock = node_base_->acquire_notify_guard_condition_lock();
@@ -91,7 +83,7 @@ rclcpp::SubscriptionBase::SharedPtr
NodeTopics::create_subscription(
const std::string & topic_name,
const rclcpp::SubscriptionFactory & subscription_factory,
const rcl_subscription_options_t & subscription_options,
rcl_subscription_options_t & subscription_options,
bool use_intra_process)
{
auto subscription = subscription_factory.create_typed_subscription(
@@ -100,12 +92,10 @@ NodeTopics::create_subscription(
// Setup intra process publishing if requested.
if (use_intra_process) {
auto context = node_base_->get_context();
auto ipm =
auto intra_process_manager =
context->get_sub_context<rclcpp::intra_process_manager::IntraProcessManager>();
uint64_t intra_process_subscription_id = ipm->add_subscription(subscription);
auto options_copy = subscription_options;
options_copy.ignore_local_publications = false;
subscription->setup_intra_process(intra_process_subscription_id, ipm, options_copy);
subscription_factory.setup_intra_process(
intra_process_manager, subscription, subscription_options);
}
// Return the completed subscription.
@@ -123,13 +113,9 @@ NodeTopics::add_subscription(
// TODO(jacquelinekay): use custom exception
throw std::runtime_error("Cannot create subscription, callback group not in node.");
}
callback_group->add_subscription(subscription);
} else {
callback_group = node_base_->get_default_callback_group();
}
callback_group->add_subscription(subscription);
for (auto & subscription_event : subscription->get_event_handlers()) {
callback_group->add_waitable(subscription_event);
node_base_->get_default_callback_group()->add_subscription(subscription);
}
// Notify the executor that a new subscription was created using the parent Node.
@@ -143,9 +129,3 @@ NodeTopics::add_subscription(
}
}
}
rclcpp::node_interfaces::NodeBaseInterface *
NodeTopics::get_node_base_interface() const
{
return node_base_;
}

View File

@@ -1,313 +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.
#include "rclcpp/node_options.hpp"
#include <limits>
#include <memory>
#include <string>
#include <vector>
#include "rclcpp/exceptions.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/publisher_options.hpp"
#include "rclcpp/qos.hpp"
using rclcpp::exceptions::throw_from_rcl_error;
namespace rclcpp
{
namespace detail
{
static
void
rcl_node_options_t_destructor(rcl_node_options_t * node_options)
{
if (node_options) {
rcl_ret_t ret = rcl_node_options_fini(node_options);
if (RCL_RET_OK != ret) {
// Cannot throw here, as it may be called in the destructor.
RCLCPP_ERROR(
rclcpp::get_logger("rclcpp"),
"failed to finalize rcl node options: %s", rcl_get_error_string().str);
rcl_reset_error();
}
}
}
} // namespace detail
NodeOptions::NodeOptions(rcl_allocator_t allocator)
: node_options_(nullptr, detail::rcl_node_options_t_destructor), allocator_(allocator)
{}
NodeOptions::NodeOptions(const NodeOptions & other)
: node_options_(nullptr, detail::rcl_node_options_t_destructor)
{
*this = other;
}
NodeOptions &
NodeOptions::operator=(const NodeOptions & other)
{
if (this != &other) {
this->context_ = other.context_;
this->arguments_ = other.arguments_;
this->initial_parameters_ = other.initial_parameters_;
this->use_global_arguments_ = other.use_global_arguments_;
this->use_intra_process_comms_ = other.use_intra_process_comms_;
this->start_parameter_services_ = other.start_parameter_services_;
this->allocator_ = other.allocator_;
this->allow_undeclared_parameters_ = other.allow_undeclared_parameters_;
this->automatically_declare_initial_parameters_ =
other.automatically_declare_initial_parameters_;
}
return *this;
}
const rcl_node_options_t *
NodeOptions::get_rcl_node_options() const
{
// If it is nullptr, create it on demand.
if (!node_options_) {
node_options_.reset(new rcl_node_options_t);
*node_options_ = rcl_node_get_default_options();
node_options_->allocator = this->allocator_;
node_options_->use_global_arguments = this->use_global_arguments_;
node_options_->domain_id = this->get_domain_id_from_env();
std::unique_ptr<const char *[]> c_args;
if (!this->arguments_.empty()) {
c_args.reset(new const char *[this->arguments_.size()]);
for (std::size_t i = 0; i < this->arguments_.size(); ++i) {
c_args[i] = this->arguments_[i].c_str();
}
}
if (this->arguments_.size() > std::numeric_limits<int>::max()) {
throw_from_rcl_error(RCL_RET_INVALID_ARGUMENT, "Too many args");
}
rmw_ret_t ret = rcl_parse_arguments(
static_cast<int>(this->arguments_.size()), c_args.get(), this->allocator_,
&(node_options_->arguments));
if (RCL_RET_OK != ret) {
throw_from_rcl_error(ret, "failed to parse arguments");
}
}
return node_options_.get();
}
rclcpp::Context::SharedPtr
NodeOptions::context() const
{
return this->context_;
}
NodeOptions &
NodeOptions::context(rclcpp::Context::SharedPtr context)
{
this->context_ = context;
return *this;
}
const std::vector<std::string> &
NodeOptions::arguments() const
{
return this->arguments_;
}
NodeOptions &
NodeOptions::arguments(const std::vector<std::string> & arguments)
{
this->node_options_.reset(); // reset node options to make it be recreated on next access.
this->arguments_ = arguments;
return *this;
}
std::vector<rclcpp::Parameter> &
NodeOptions::initial_parameters()
{
return this->initial_parameters_;
}
const std::vector<rclcpp::Parameter> &
NodeOptions::initial_parameters() const
{
return this->initial_parameters_;
}
NodeOptions &
NodeOptions::initial_parameters(const std::vector<rclcpp::Parameter> & initial_parameters)
{
this->initial_parameters_ = initial_parameters;
return *this;
}
bool
NodeOptions::use_global_arguments() const
{
return this->node_options_->use_global_arguments;
}
NodeOptions &
NodeOptions::use_global_arguments(bool use_global_arguments)
{
this->node_options_.reset(); // reset node options to make it be recreated on next access.
this->use_global_arguments_ = use_global_arguments;
return *this;
}
bool
NodeOptions::use_intra_process_comms() const
{
return this->use_intra_process_comms_;
}
NodeOptions &
NodeOptions::use_intra_process_comms(bool use_intra_process_comms)
{
this->use_intra_process_comms_ = use_intra_process_comms;
return *this;
}
bool
NodeOptions::start_parameter_services() const
{
return this->start_parameter_services_;
}
NodeOptions &
NodeOptions::start_parameter_services(bool start_parameter_services)
{
this->start_parameter_services_ = start_parameter_services;
return *this;
}
bool
NodeOptions::start_parameter_event_publisher() const
{
return this->start_parameter_event_publisher_;
}
NodeOptions &
NodeOptions::start_parameter_event_publisher(bool start_parameter_event_publisher)
{
this->start_parameter_event_publisher_ = start_parameter_event_publisher;
return *this;
}
const rclcpp::QoS &
NodeOptions::parameter_event_qos() const
{
return this->parameter_event_qos_;
}
NodeOptions &
NodeOptions::parameter_event_qos(const rclcpp::QoS & parameter_event_qos)
{
this->parameter_event_qos_ = parameter_event_qos;
return *this;
}
const rclcpp::PublisherOptionsBase &
NodeOptions::parameter_event_publisher_options() const
{
return parameter_event_publisher_options_;
}
NodeOptions &
NodeOptions::parameter_event_publisher_options(
const rclcpp::PublisherOptionsBase & parameter_event_publisher_options)
{
parameter_event_publisher_options_ = parameter_event_publisher_options;
return *this;
}
bool
NodeOptions::allow_undeclared_parameters() const
{
return this->allow_undeclared_parameters_;
}
NodeOptions &
NodeOptions::allow_undeclared_parameters(bool allow_undeclared_parameters)
{
this->allow_undeclared_parameters_ = allow_undeclared_parameters;
return *this;
}
bool
NodeOptions::automatically_declare_initial_parameters() const
{
return this->automatically_declare_initial_parameters_;
}
NodeOptions &
NodeOptions::automatically_declare_initial_parameters(
bool automatically_declare_initial_parameters)
{
this->automatically_declare_initial_parameters_ = automatically_declare_initial_parameters;
return *this;
}
const rcl_allocator_t &
NodeOptions::allocator() const
{
return this->allocator_;
}
NodeOptions &
NodeOptions::allocator(rcl_allocator_t allocator)
{
this->node_options_.reset(); // reset node options to make it be recreated on next access.
this->allocator_ = allocator;
return *this;
}
// TODO(wjwwood): reuse rcutils_get_env() to avoid code duplication.
// See also: https://github.com/ros2/rcl/issues/119
size_t
NodeOptions::get_domain_id_from_env() const
{
// Determine the domain id based on the options and the ROS_DOMAIN_ID env variable.
size_t domain_id = std::numeric_limits<size_t>::max();
char * ros_domain_id = nullptr;
const char * env_var = "ROS_DOMAIN_ID";
#ifndef _WIN32
ros_domain_id = getenv(env_var);
#else
size_t ros_domain_id_size;
_dupenv_s(&ros_domain_id, &ros_domain_id_size, env_var);
#endif
if (ros_domain_id) {
uint32_t number = strtoul(ros_domain_id, NULL, 0);
if (number == (std::numeric_limits<uint32_t>::max)()) {
#ifdef _WIN32
// free the ros_domain_id before throwing, if getenv was used on Windows
free(ros_domain_id);
#endif
throw std::runtime_error("failed to interpret ROS_DOMAIN_ID as integral number");
}
domain_id = static_cast<size_t>(number);
#ifdef _WIN32
free(ros_domain_id);
#endif
}
return domain_id;
}
} // namespace rclcpp

View File

@@ -19,17 +19,7 @@
#include <string>
#include <vector>
// When compiling this file, Windows produces a deprecation warning for the
// deprecated function prototype of NodeParameters::register_param_change_callback().
// Other compilers do not.
#if defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
#include "rclcpp/node_interfaces/node_parameters.hpp"
#if defined(_WIN32)
# pragma warning(pop)
#endif
#include "rclcpp/utilities.hpp"
using rclcpp::ParameterType;
@@ -40,11 +30,6 @@ Parameter::Parameter()
{
}
Parameter::Parameter(const std::string & name)
: name_(name), value_()
{
}
Parameter::Parameter(const std::string & name, const rclcpp::ParameterValue & value)
: name_(name), value_(value)
{
@@ -55,18 +40,6 @@ Parameter::Parameter(const rclcpp::node_interfaces::ParameterInfo & parameter_in
{
}
bool
Parameter::operator==(const Parameter & rhs) const
{
return this->name_ == rhs.name_ && this->value_ == rhs.value_;
}
bool
Parameter::operator!=(const Parameter & rhs) const
{
return !(*this == rhs);
}
ParameterType
Parameter::get_type() const
{

View File

@@ -227,15 +227,3 @@ ParameterValue::to_value_msg() const
{
return value_;
}
bool
ParameterValue::operator==(const ParameterValue & rhs) const
{
return this->value_ == rhs.value_;
}
bool
ParameterValue::operator!=(const ParameterValue & rhs) const
{
return this->value_ != rhs.value_;
}

View File

@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "rclcpp/publisher_base.hpp"
#include "rclcpp/publisher.hpp"
#include <rmw/error_handling.h>
#include <rmw/rmw.h>
@@ -22,7 +22,6 @@
#include <mutex>
#include <sstream>
#include <string>
#include <vector>
#include "rcl_interfaces/msg/intra_process_message.hpp"
#include "rcutils/logging_macros.h"
@@ -31,10 +30,9 @@
#include "rclcpp/allocator/allocator_common.hpp"
#include "rclcpp/allocator/allocator_deleter.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/expand_topic_or_service_name.hpp"
#include "rclcpp/intra_process_manager.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/expand_topic_or_service_name.hpp"
using rclcpp::PublisherBase;
@@ -44,7 +42,7 @@ PublisherBase::PublisherBase(
const rosidl_message_type_support_t & type_support,
const rcl_publisher_options_t & publisher_options)
: rcl_node_handle_(node_base->get_shared_rcl_node_handle()),
intra_process_is_enabled_(false), intra_process_publisher_id_(0)
intra_process_publisher_id_(0), store_intra_process_message_(nullptr)
{
rcl_ret_t ret = rcl_publisher_init(
&publisher_handle_,
@@ -81,9 +79,6 @@ PublisherBase::PublisherBase(
PublisherBase::~PublisherBase()
{
// must fini the events before fini-ing the publisher
event_handlers_.clear();
if (rcl_publisher_fini(&intra_process_publisher_handle_, rcl_node_handle_.get()) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
@@ -99,20 +94,6 @@ PublisherBase::~PublisherBase()
rcl_get_error_string().str);
rcl_reset_error();
}
auto ipm = weak_ipm_.lock();
if (!intra_process_is_enabled_) {
return;
}
if (!ipm) {
// TODO(ivanpauno): should this raise an error?
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Intra process manager died before than a publisher.");
return;
}
ipm->remove_publisher(intra_process_publisher_id_);
}
const char *
@@ -157,72 +138,6 @@ PublisherBase::get_publisher_handle() const
return &publisher_handle_;
}
const std::vector<std::shared_ptr<rclcpp::QOSEventHandlerBase>> &
PublisherBase::get_event_handlers() const
{
return event_handlers_;
}
size_t
PublisherBase::get_subscription_count() const
{
size_t inter_process_subscription_count = 0;
rcl_ret_t status = rcl_publisher_get_subscription_count(
&publisher_handle_,
&inter_process_subscription_count);
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 (nullptr != context && !rcl_context_is_valid(context)) {
/* publisher is invalid due to context being shutdown */
return 0;
}
}
}
if (RCL_RET_OK != status) {
rclcpp::exceptions::throw_from_rcl_error(status, "failed to get get subscription count");
}
return inter_process_subscription_count;
}
size_t
PublisherBase::get_intra_process_subscription_count() const
{
auto ipm = weak_ipm_.lock();
if (!intra_process_is_enabled_) {
return 0;
}
if (!ipm) {
// TODO(ivanpauno): should this just return silently? Or maybe return with a warning?
// Same as wjwwood comment in publisher_factory create_shared_publish_callback.
throw std::runtime_error(
"intra process subscriber count called after "
"destruction of intra process manager");
}
return ipm->get_subscription_count(intra_process_publisher_id_);
}
rmw_qos_profile_t
PublisherBase::get_actual_qos() const
{
const rmw_qos_profile_t * qos = rcl_publisher_get_actual_qos(&publisher_handle_);
if (!qos) {
auto msg = std::string("failed to get qos settings: ") + rcl_get_error_string().str;
rcl_reset_error();
throw std::runtime_error(msg);
}
return *qos;
}
bool
PublisherBase::assert_liveliness() const
{
return RCL_RET_OK == rcl_publisher_assert_liveliness(&publisher_handle_);
}
bool
PublisherBase::operator==(const rmw_gid_t & gid) const
{
@@ -250,24 +165,12 @@ PublisherBase::operator==(const rmw_gid_t * gid) const
return result;
}
rclcpp::mapped_ring_buffer::MappedRingBufferBase::SharedPtr
PublisherBase::make_mapped_ring_buffer(size_t size) const
{
(void)size;
return nullptr;
}
void
PublisherBase::setup_intra_process(
uint64_t intra_process_publisher_id,
IntraProcessManagerSharedPtr ipm,
StoreMessageCallbackT callback,
const rcl_publisher_options_t & intra_process_options)
{
// Intraprocess configuration is not allowed with "durability" qos policy non "volatile".
if (this->get_actual_qos().durability != RMW_QOS_POLICY_DURABILITY_VOLATILE) {
throw exceptions::InvalidParametersException(
"intraprocess communication is not allowed with durability qos policy non-volatile");
}
const char * topic_name = this->get_topic_name();
if (!topic_name) {
throw std::runtime_error("failed to get topic name");
@@ -296,9 +199,7 @@ PublisherBase::setup_intra_process(
}
intra_process_publisher_id_ = intra_process_publisher_id;
weak_ipm_ = ipm;
intra_process_is_enabled_ = true;
store_intra_process_message_ = callback;
// Life time of this object is tied to the publisher handle.
rmw_publisher_t * publisher_rmw_handle = rcl_publisher_get_rmw_handle(
&intra_process_publisher_handle_);

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.
#include "rclcpp/qos.hpp"
#include <rmw/types.h>
namespace rclcpp
{
QoSInitialization::QoSInitialization(rmw_qos_history_policy_t history_policy_arg, size_t depth_arg)
: history_policy(history_policy_arg), depth(depth_arg)
{}
QoSInitialization
QoSInitialization::from_rmw(const rmw_qos_profile_t & rmw_qos)
{
switch (rmw_qos.history) {
case RMW_QOS_POLICY_HISTORY_KEEP_ALL:
return KeepAll();
case RMW_QOS_POLICY_HISTORY_KEEP_LAST:
case RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT:
case RMW_QOS_POLICY_HISTORY_UNKNOWN:
default:
return KeepLast(rmw_qos.depth);
}
}
KeepAll::KeepAll()
: QoSInitialization(RMW_QOS_POLICY_HISTORY_KEEP_ALL, 0)
{}
KeepLast::KeepLast(size_t depth)
: QoSInitialization(RMW_QOS_POLICY_HISTORY_KEEP_LAST, depth)
{}
QoS::QoS(
const QoSInitialization & qos_initialization,
const rmw_qos_profile_t & initial_profile)
: rmw_qos_profile_(initial_profile)
{
rmw_qos_profile_.history = qos_initialization.history_policy;
rmw_qos_profile_.depth = qos_initialization.depth;
}
QoS::QoS(size_t history_depth)
: QoS(KeepLast(history_depth))
{}
rmw_qos_profile_t &
QoS::get_rmw_qos_profile()
{
return rmw_qos_profile_;
}
const rmw_qos_profile_t &
QoS::get_rmw_qos_profile() const
{
return rmw_qos_profile_;
}
QoS &
QoS::history(rmw_qos_history_policy_t history)
{
rmw_qos_profile_.history = history;
return *this;
}
QoS &
QoS::keep_last(size_t depth)
{
rmw_qos_profile_.history = RMW_QOS_POLICY_HISTORY_KEEP_LAST;
rmw_qos_profile_.depth = depth;
return *this;
}
QoS &
QoS::keep_all()
{
rmw_qos_profile_.history = RMW_QOS_POLICY_HISTORY_KEEP_ALL;
rmw_qos_profile_.depth = 0;
return *this;
}
QoS &
QoS::reliability(rmw_qos_reliability_policy_t reliability)
{
rmw_qos_profile_.reliability = reliability;
return *this;
}
QoS &
QoS::reliable()
{
return this->reliability(RMW_QOS_POLICY_RELIABILITY_RELIABLE);
}
QoS &
QoS::best_effort()
{
return this->reliability(RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT);
}
QoS &
QoS::durability(rmw_qos_durability_policy_t durability)
{
rmw_qos_profile_.durability = durability;
return *this;
}
QoS &
QoS::volitile()
{
return this->durability(RMW_QOS_POLICY_DURABILITY_VOLATILE);
}
QoS &
QoS::transient_local()
{
return this->durability(RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL);
}
QoS &
QoS::deadline(rmw_time_t deadline)
{
rmw_qos_profile_.deadline = deadline;
return *this;
}
QoS &
QoS::deadline(const rclcpp::Duration & deadline)
{
return this->deadline(deadline.to_rmw_time());
}
QoS &
QoS::lifespan(rmw_time_t lifespan)
{
rmw_qos_profile_.lifespan = lifespan;
return *this;
}
QoS &
QoS::lifespan(const rclcpp::Duration & lifespan)
{
return this->lifespan(lifespan.to_rmw_time());
}
QoS &
QoS::liveliness(rmw_qos_liveliness_policy_t liveliness)
{
rmw_qos_profile_.liveliness = liveliness;
return *this;
}
QoS &
QoS::liveliness_lease_duration(rmw_time_t liveliness_lease_duration)
{
rmw_qos_profile_.liveliness_lease_duration = liveliness_lease_duration;
return *this;
}
QoS &
QoS::liveliness_lease_duration(const rclcpp::Duration & liveliness_lease_duration)
{
return this->liveliness_lease_duration(liveliness_lease_duration.to_rmw_time());
}
QoS &
QoS::avoid_ros_namespace_conventions(bool avoid_ros_namespace_conventions)
{
rmw_qos_profile_.avoid_ros_namespace_conventions = avoid_ros_namespace_conventions;
return *this;
}
SensorDataQoS::SensorDataQoS(const QoSInitialization & qos_initialization)
: QoS(qos_initialization, rmw_qos_profile_sensor_data)
{}
ParametersQoS::ParametersQoS(const QoSInitialization & qos_initialization)
: QoS(qos_initialization, rmw_qos_profile_parameters)
{}
ServicesQoS::ServicesQoS(const QoSInitialization & qos_initialization)
: QoS(qos_initialization, rmw_qos_profile_services_default)
{}
ParameterEventsQoS::ParameterEventsQoS(const QoSInitialization & qos_initialization)
: QoS(qos_initialization, rmw_qos_profile_parameter_events)
{}
SystemDefaultsQoS::SystemDefaultsQoS(const QoSInitialization & qos_initialization)
: QoS(qos_initialization, rmw_qos_profile_system_default)
{}
} // namespace rclcpp

View File

@@ -1,55 +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.
#include "rclcpp/qos_event.hpp"
namespace rclcpp
{
QOSEventHandlerBase::~QOSEventHandlerBase()
{
if (rcl_event_fini(&event_handle_) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Error in destruction of rcl event handle: %s", rcl_get_error_string().str);
rcl_reset_error();
}
}
/// Get the number of ready events.
size_t
QOSEventHandlerBase::get_number_of_ready_events()
{
return 1;
}
/// Add the Waitable to a wait set.
bool
QOSEventHandlerBase::add_to_wait_set(rcl_wait_set_t * wait_set)
{
rcl_ret_t ret = rcl_wait_set_add_event(wait_set, &event_handle_, &wait_set_event_index_);
if (RCL_RET_OK != ret) {
exceptions::throw_from_rcl_error(ret, "Couldn't add event to wait set");
}
return true;
}
/// Check if the Waitable is ready.
bool
QOSEventHandlerBase::is_ready(rcl_wait_set_t * wait_set)
{
return wait_set->events[wait_set_event_index_] == &event_handle_;
}
} // namespace rclcpp

View File

@@ -46,38 +46,18 @@ dispatch_semaphore_t SignalHandler::signal_handler_sem_;
sem_t SignalHandler::signal_handler_sem_;
#endif
// The logger must be initialized before the local static variable signal_handler,
// from the method get_global_signal_handler(), so that it is destructed after
// it, because the destructor of SignalHandler uses this logger object.
static rclcpp::Logger g_logger = rclcpp::get_logger("rclcpp");
SignalHandler &
SignalHandler::get_global_signal_handler()
{
static SignalHandler signal_handler;
return signal_handler;
}
rclcpp::Logger &
SignalHandler::get_logger()
{
return g_logger;
}
SignalHandler &
SignalHandler::get_global_signal_handler()
{
// This is initialized after the g_logger static global, ensuring
// SignalHandler::get_logger() may be called from the destructor of
// SignalHandler, according to this:
//
// Variables declared at block scope with the specifier static have static
// storage duration but are initialized the first time control passes
// through their declaration (unless their initialization is zero- or
// constant-initialization, which can be performed before the block is
// first entered). On all further calls, the declaration is skipped.
//
// -- https://en.cppreference.com/w/cpp/language/storage_duration#Static_local_variables
//
// Which is guaranteed to occur after static initialization for global (see:
// https://en.cppreference.com/w/cpp/language/initialization#Static_initialization),
// which is when g_logger will be initialized.
// And destruction will occur in the reverse order.
static SignalHandler signal_handler;
return signal_handler;
static rclcpp::Logger logger = rclcpp::get_logger("rclcpp");
return logger;
}
bool

View File

@@ -12,16 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "rclcpp/subscription_base.hpp"
#include "rclcpp/subscription.hpp"
#include <cstdio>
#include <memory>
#include <string>
#include <vector>
#include "rclcpp/exceptions.hpp"
#include "rclcpp/expand_topic_or_service_name.hpp"
#include "rclcpp/intra_process_manager.hpp"
#include "rclcpp/logging.hpp"
#include "rmw/error_handling.h"
@@ -36,8 +34,6 @@ SubscriptionBase::SubscriptionBase(
const rcl_subscription_options_t & subscription_options,
bool is_serialized)
: node_handle_(node_handle),
use_intra_process_(false),
intra_process_subscription_id_(0),
type_support_(type_support_handle),
is_serialized_(is_serialized)
{
@@ -84,18 +80,6 @@ SubscriptionBase::SubscriptionBase(
SubscriptionBase::~SubscriptionBase()
{
if (!use_intra_process_) {
return;
}
auto ipm = weak_ipm_.lock();
if (!ipm) {
// TODO(ivanpauno): should this raise an error?
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Intra process manager died before than a subscription.");
return;
}
ipm->remove_subscription(intra_process_subscription_id_);
}
const char *
@@ -122,12 +106,6 @@ SubscriptionBase::get_intra_process_subscription_handle() const
return intra_process_subscription_handle_;
}
const std::vector<std::shared_ptr<rclcpp::QOSEventHandlerBase>> &
SubscriptionBase::get_event_handlers() const
{
return event_handlers_;
}
const rosidl_message_type_support_t &
SubscriptionBase::get_message_type_support_handle() const
{
@@ -139,49 +117,3 @@ SubscriptionBase::is_serialized() const
{
return is_serialized_;
}
size_t
SubscriptionBase::get_publisher_count() const
{
size_t inter_process_publisher_count = 0;
rmw_ret_t status = rcl_subscription_get_publisher_count(
subscription_handle_.get(),
&inter_process_publisher_count);
if (RCL_RET_OK != status) {
rclcpp::exceptions::throw_from_rcl_error(status, "failed to get get publisher count");
}
return inter_process_publisher_count;
}
void SubscriptionBase::setup_intra_process(
uint64_t intra_process_subscription_id,
IntraProcessManagerWeakPtr weak_ipm,
const rcl_subscription_options_t & intra_process_options)
{
std::string intra_process_topic_name = std::string(get_topic_name()) + "/_intra";
rcl_ret_t ret = rcl_subscription_init(
intra_process_subscription_handle_.get(),
node_handle_.get(),
rclcpp::type_support::get_intra_process_message_msg_type_support(),
intra_process_topic_name.c_str(),
&intra_process_options);
if (ret != RCL_RET_OK) {
if (ret == RCL_RET_TOPIC_NAME_INVALID) {
auto rcl_node_handle = node_handle_.get();
// this will throw on any validation problem
rcl_reset_error();
expand_topic_or_service_name(
intra_process_topic_name,
rcl_node_get_name(rcl_node_handle),
rcl_node_get_namespace(rcl_node_handle));
}
rclcpp::exceptions::throw_from_rcl_error(ret, "could not create intra process subscription");
}
intra_process_subscription_id_ = intra_process_subscription_id;
weak_ipm_ = weak_ipm;
use_intra_process_ = true;
}

View File

@@ -28,6 +28,7 @@
#include "rclcpp/time.hpp"
#include "rclcpp/time_source.hpp"
namespace rclcpp
{
@@ -77,29 +78,20 @@ void TimeSource::attachNode(
logger_ = node_logging_->get_logger();
// Though this defaults to false, it can be overridden by initial parameter values for the node,
// which may be given by the user at the node's construction or even by command-line arguments.
rclcpp::ParameterValue use_sim_time_param;
const char * use_sim_time_name = "use_sim_time";
if (!node_parameters_->has_parameter(use_sim_time_name)) {
use_sim_time_param = node_parameters_->declare_parameter(
use_sim_time_name,
rclcpp::ParameterValue(false),
rcl_interfaces::msg::ParameterDescriptor());
} else {
use_sim_time_param = node_parameters_->get_parameter(use_sim_time_name).get_parameter_value();
}
if (use_sim_time_param.get_type() == rclcpp::PARAMETER_BOOL) {
if (use_sim_time_param.get<bool>()) {
parameter_state_ = SET_TRUE;
enable_ros_time();
create_clock_sub();
rclcpp::Parameter use_sim_time_param;
if (node_parameters_->get_parameter("use_sim_time", use_sim_time_param)) {
if (use_sim_time_param.get_type() == rclcpp::PARAMETER_BOOL) {
if (use_sim_time_param.get_value<bool>() == true) {
parameter_state_ = SET_TRUE;
enable_ros_time();
create_clock_sub();
}
} else {
RCLCPP_ERROR(logger_, "Invalid type for parameter 'use_sim_time' %s should be bool",
use_sim_time_param.get_type_name().c_str());
}
} else {
// TODO(wjwwood): use set_on_parameters_set_callback to catch the type mismatch,
// before the use_sim_time parameter can ever be set to an invalid value
RCLCPP_ERROR(logger_, "Invalid type '%s' for parameter 'use_sim_time', should be 'bool'",
rclcpp::to_string(use_sim_time_param.get_type()).c_str());
RCLCPP_DEBUG(logger_, "'use_sim_time' parameter not set, using wall time by default.");
}
// TODO(tfoote) use parameters interface not subscribe to events via topic ticketed #609
@@ -207,13 +199,26 @@ void TimeSource::create_clock_sub()
// Subscription already created.
return;
}
const std::string topic_name = "/clock";
clock_subscription_ = rclcpp::create_subscription<rosgraph_msgs::msg::Clock>(
node_topics_,
"/clock",
rclcpp::QoS(QoSInitialization::from_rmw(rmw_qos_profile_default)),
std::bind(&TimeSource::clock_cb, this, std::placeholders::_1)
);
rclcpp::callback_group::CallbackGroup::SharedPtr group;
using rclcpp::message_memory_strategy::MessageMemoryStrategy;
auto msg_mem_strat = MessageMemoryStrategy<MessageT, Alloc>::create_default();
auto allocator = std::make_shared<Alloc>();
auto cb = std::bind(&TimeSource::clock_cb, this, std::placeholders::_1);
clock_subscription_ = rclcpp::create_subscription<
MessageT, decltype(cb), Alloc, MessageT, SubscriptionT
>(
node_topics_.get(),
topic_name,
std::move(cb),
rmw_qos_profile_default,
group,
false,
false,
msg_mem_strat,
allocator);
}
void TimeSource::destroy_clock_sub()

View File

@@ -19,8 +19,6 @@
#include <memory>
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/exceptions.hpp"
#include "rcutils/logging_macros.h"
using rclcpp::TimerBase;
@@ -77,17 +75,6 @@ TimerBase::cancel()
}
}
bool
TimerBase::is_canceled()
{
bool is_canceled = false;
rcl_ret_t ret = rcl_timer_is_canceled(timer_handle_.get(), &is_canceled);
if (ret != RCL_RET_OK) {
rclcpp::exceptions::throw_from_rcl_error(ret, "Couldn't get timer cancelled state");
}
return is_canceled;
}
void
TimerBase::reset()
{

View File

@@ -24,48 +24,45 @@
#include "rcl/error_handling.h"
#include "rcl/rcl.h"
namespace rclcpp
{
void
init(int argc, char const * const argv[], const InitOptions & init_options)
rclcpp::init(int argc, char const * const argv[], const rclcpp::InitOptions & init_options)
{
using contexts::default_context::get_global_default_context;
using rclcpp::contexts::default_context::get_global_default_context;
get_global_default_context()->init(argc, argv, init_options);
// Install the signal handlers.
install_signal_handlers();
rclcpp::install_signal_handlers();
}
bool
install_signal_handlers()
rclcpp::install_signal_handlers()
{
return SignalHandler::get_global_signal_handler().install();
return rclcpp::SignalHandler::get_global_signal_handler().install();
}
bool
signal_handlers_installed()
rclcpp::signal_handlers_installed()
{
return SignalHandler::get_global_signal_handler().is_installed();
return rclcpp::SignalHandler::get_global_signal_handler().is_installed();
}
bool
uninstall_signal_handlers()
rclcpp::uninstall_signal_handlers()
{
return SignalHandler::get_global_signal_handler().uninstall();
return rclcpp::SignalHandler::get_global_signal_handler().uninstall();
}
std::vector<std::string>
init_and_remove_ros_arguments(
rclcpp::init_and_remove_ros_arguments(
int argc,
char const * const argv[],
const InitOptions & init_options)
const rclcpp::InitOptions & init_options)
{
init(argc, argv, init_options);
return remove_ros_arguments(argc, argv);
rclcpp::init(argc, argv, init_options);
return rclcpp::remove_ros_arguments(argc, argv);
}
std::vector<std::string>
remove_ros_arguments(int argc, char const * const argv[])
rclcpp::remove_ros_arguments(int argc, char const * const argv[])
{
rcl_allocator_t alloc = rcl_get_default_allocator();
rcl_arguments_t parsed_args = rcl_get_zero_initialized_arguments();
@@ -74,7 +71,7 @@ remove_ros_arguments(int argc, char const * const argv[])
ret = rcl_parse_arguments(argc, argv, alloc, &parsed_args);
if (RCL_RET_OK != ret) {
exceptions::throw_from_rcl_error(ret, "failed to parse arguments");
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to parse arguments");
}
int nonros_argc = 0;
@@ -87,9 +84,9 @@ remove_ros_arguments(int argc, char const * const argv[])
&nonros_argc,
&nonros_argv);
if (RCL_RET_OK != ret || nonros_argc < 0) {
if (RCL_RET_OK != ret) {
// Not using throw_from_rcl_error, because we may need to append deallocation failures.
exceptions::RCLErrorBase base_exc(ret, rcl_get_error_state());
rclcpp::exceptions::RCLErrorBase base_exc(ret, rcl_get_error_state());
rcl_reset_error();
if (NULL != nonros_argv) {
alloc.deallocate(nonros_argv, alloc.state);
@@ -100,10 +97,11 @@ remove_ros_arguments(int argc, char const * const argv[])
rcl_get_error_string().str;
rcl_reset_error();
}
throw exceptions::RCLError(base_exc, "");
throw rclcpp::exceptions::RCLError(base_exc, "");
}
std::vector<std::string> return_arguments(nonros_argc);
std::vector<std::string> return_arguments;
return_arguments.resize(nonros_argc);
for (int ii = 0; ii < nonros_argc; ++ii) {
return_arguments[ii] = std::string(nonros_argv[ii]);
@@ -115,7 +113,7 @@ remove_ros_arguments(int argc, char const * const argv[])
ret = rcl_arguments_fini(&parsed_args);
if (RCL_RET_OK != ret) {
exceptions::throw_from_rcl_error(
rclcpp::exceptions::throw_from_rcl_error(
ret, "failed to cleanup parsed arguments, leaking memory");
}
@@ -123,9 +121,9 @@ remove_ros_arguments(int argc, char const * const argv[])
}
bool
ok(Context::SharedPtr context)
rclcpp::ok(rclcpp::Context::SharedPtr context)
{
using contexts::default_context::get_global_default_context;
using rclcpp::contexts::default_context::get_global_default_context;
if (nullptr == context) {
context = get_global_default_context();
}
@@ -133,30 +131,30 @@ ok(Context::SharedPtr context)
}
bool
is_initialized(Context::SharedPtr context)
rclcpp::is_initialized(rclcpp::Context::SharedPtr context)
{
return ok(context);
return rclcpp::ok(context);
}
bool
shutdown(Context::SharedPtr context, const std::string & reason)
rclcpp::shutdown(rclcpp::Context::SharedPtr context, const std::string & reason)
{
using contexts::default_context::get_global_default_context;
using rclcpp::contexts::default_context::get_global_default_context;
auto default_context = get_global_default_context();
if (nullptr == context) {
context = default_context;
}
bool ret = context->shutdown(reason);
if (context == default_context) {
uninstall_signal_handlers();
rclcpp::uninstall_signal_handlers();
}
return ret;
}
void
on_shutdown(std::function<void()> callback, Context::SharedPtr context)
rclcpp::on_shutdown(std::function<void()> callback, rclcpp::Context::SharedPtr context)
{
using contexts::default_context::get_global_default_context;
using rclcpp::contexts::default_context::get_global_default_context;
if (nullptr == context) {
context = get_global_default_context();
}
@@ -164,9 +162,9 @@ on_shutdown(std::function<void()> callback, Context::SharedPtr context)
}
bool
sleep_for(const std::chrono::nanoseconds & nanoseconds, Context::SharedPtr context)
rclcpp::sleep_for(const std::chrono::nanoseconds & nanoseconds, rclcpp::Context::SharedPtr context)
{
using contexts::default_context::get_global_default_context;
using rclcpp::contexts::default_context::get_global_default_context;
if (nullptr == context) {
context = get_global_default_context();
}
@@ -174,15 +172,13 @@ sleep_for(const std::chrono::nanoseconds & nanoseconds, Context::SharedPtr conte
}
const char *
get_c_string(const char * string_in)
rclcpp::get_c_string(const char * string_in)
{
return string_in;
}
const char *
get_c_string(const std::string & string_in)
rclcpp::get_c_string(const std::string & string_in)
{
return string_in.c_str();
}
} // namespace rclcpp

View File

@@ -34,12 +34,6 @@ Waitable::get_number_of_ready_clients()
return 0u;
}
size_t
Waitable::get_number_of_ready_events()
{
return 0u;
}
size_t
Waitable::get_number_of_ready_services()
{

View File

@@ -1,64 +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 NODE_INTERFACES__NODE_WRAPPER_HPP_
#define NODE_INTERFACES__NODE_WRAPPER_HPP_
#include <memory>
#include <string>
#include "rclcpp/rclcpp.hpp"
class NodeWrapper
{
public:
explicit NodeWrapper(const std::string & name)
: node(std::make_shared<rclcpp::Node>(name))
{}
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
get_node_base_interface() {return this->node->get_node_base_interface();}
rclcpp::node_interfaces::NodeClockInterface::SharedPtr
get_node_clock_interface() {return this->node->get_node_clock_interface();}
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr
get_node_graph_interface() {return this->node->get_node_graph_interface();}
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr
get_node_logging_interface() {return this->node->get_node_logging_interface();}
rclcpp::node_interfaces::NodeTimersInterface::SharedPtr
get_node_timers_interface() {return this->node->get_node_timers_interface();}
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr
get_node_topics_interface() {return this->node->get_node_topics_interface();}
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr
get_node_services_interface() {return this->node->get_node_services_interface();}
rclcpp::node_interfaces::NodeWaitablesInterface::SharedPtr
get_node_waitables_interface() {return this->node->get_node_waitables_interface();}
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr
get_node_parameters_interface() {return this->node->get_node_parameters_interface();}
rclcpp::node_interfaces::NodeTimeSourceInterface::SharedPtr
get_node_time_source_interface() {return this->node->get_node_time_source_interface();}
private:
rclcpp::Node::SharedPtr node;
};
#endif // NODE_INTERFACES__NODE_WRAPPER_HPP_

View File

@@ -1,28 +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.
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/node_interfaces/get_node_topics_interface.hpp"
int main(void)
{
auto node = std::make_shared<rclcpp::Node>("test_node");
std::shared_ptr<const rclcpp::Node> const_node_ptr = node;
// Should fail because a const node cannot have a non-const method called on it.
rclcpp::node_interfaces::NodeTopicsInterface * result =
rclcpp::node_interfaces::get_node_topics_interface(const_node_ptr);
(void)result;
}

View File

@@ -1,30 +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.
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/node_interfaces/get_node_topics_interface.hpp"
#include "../node_wrapper.hpp"
int main(void)
{
auto node = std::make_shared<NodeWrapper>("test_wrapped_node");
std::shared_ptr<const NodeWrapper> const_node_ptr = node;
// Should fail because a const node cannot have a non-const method called on it.
rclcpp::node_interfaces::NodeTopicsInterface * result =
rclcpp::node_interfaces::get_node_topics_interface(const_node_ptr);
(void)result;
}

View File

@@ -1,28 +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.
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/node_interfaces/get_node_topics_interface.hpp"
int main(void)
{
auto node = std::make_shared<rclcpp::Node>("test_node");
const rclcpp::Node & const_node_reference = *node;
// Should fail because a const node cannot have a non-const method called on it.
rclcpp::node_interfaces::NodeTopicsInterface * result =
rclcpp::node_interfaces::get_node_topics_interface(const_node_reference);
(void)result;
}

View File

@@ -1,30 +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.
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/node_interfaces/get_node_topics_interface.hpp"
#include "../node_wrapper.hpp"
int main(void)
{
auto node = std::make_shared<NodeWrapper>("test_wrapped_node");
const NodeWrapper & const_node_reference = *node;
// Should fail because a const node cannot have a non-const method called on it.
rclcpp::node_interfaces::NodeTopicsInterface * result =
rclcpp::node_interfaces::get_node_topics_interface(const_node_reference);
(void)result;
}

View File

@@ -1,97 +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.
#include <memory>
#include <string>
#include "gtest/gtest.h"
#include "rclcpp/node_interfaces/get_node_topics_interface.hpp"
#include "rclcpp/rclcpp.hpp"
#include "./node_wrapper.hpp"
static const std::string node_suffix = "test_get_node_interfaces"; // NOLINT
class TestGetNodeInterfaces : public ::testing::Test
{
protected:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
node = std::make_shared<rclcpp::Node>(node_suffix);
wrapped_node = std::make_shared<NodeWrapper>("wrapped_" + node_suffix);
}
static void TearDownTestCase()
{
node.reset();
wrapped_node.reset();
}
static rclcpp::Node::SharedPtr node;
static std::shared_ptr<NodeWrapper> wrapped_node;
};
rclcpp::Node::SharedPtr TestGetNodeInterfaces::node = nullptr;
std::shared_ptr<NodeWrapper> TestGetNodeInterfaces::wrapped_node = nullptr;
TEST_F(TestGetNodeInterfaces, rclcpp_node_shared_ptr) {
auto result = rclcpp::node_interfaces::get_node_topics_interface(this->node);
static_assert(
std::is_same<
rclcpp::node_interfaces::NodeTopicsInterface *,
decltype(result)
>::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *");
}
TEST_F(TestGetNodeInterfaces, node_shared_ptr) {
auto result = rclcpp::node_interfaces::get_node_topics_interface(this->wrapped_node);
static_assert(
std::is_same<
rclcpp::node_interfaces::NodeTopicsInterface *,
decltype(result)
>::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *");
}
TEST_F(TestGetNodeInterfaces, rclcpp_node_reference) {
rclcpp::Node & node_reference = *this->node;
auto result = rclcpp::node_interfaces::get_node_topics_interface(node_reference);
static_assert(
std::is_same<
rclcpp::node_interfaces::NodeTopicsInterface *,
decltype(result)
>::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *");
}
TEST_F(TestGetNodeInterfaces, node_reference) {
NodeWrapper & wrapped_node_reference = *this->wrapped_node;
auto result = rclcpp::node_interfaces::get_node_topics_interface(wrapped_node_reference);
static_assert(
std::is_same<
rclcpp::node_interfaces::NodeTopicsInterface *,
decltype(result)
>::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *");
}
TEST_F(TestGetNodeInterfaces, interface_shared_pointer) {
std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface> interface_shared_ptr =
this->node->get_node_topics_interface();
auto result = rclcpp::node_interfaces::get_node_topics_interface(interface_shared_ptr);
static_assert(
std::is_same<
rclcpp::node_interfaces::NodeTopicsInterface *,
decltype(result)
>::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *");
}

View File

@@ -43,28 +43,6 @@ protected:
rclcpp::Node::SharedPtr node;
};
class TestClientSub : public ::testing::Test
{
protected:
static void SetUpTestCase()
{
}
void SetUp()
{
node = std::make_shared<rclcpp::Node>("my_node", "/ns");
subnode = node->create_sub_node("sub_ns");
}
void TearDown()
{
node.reset();
}
rclcpp::Node::SharedPtr node;
rclcpp::Node::SharedPtr subnode;
};
/*
Testing client construction and destruction.
*/
@@ -80,20 +58,3 @@ TEST_F(TestClient, construction_and_destruction) {
}, rclcpp::exceptions::InvalidServiceNameError);
}
}
/*
Testing client construction and destruction for subnodes.
*/
TEST_F(TestClientSub, construction_and_destruction) {
using rcl_interfaces::srv::ListParameters;
{
auto client = subnode->create_client<ListParameters>("service");
EXPECT_STREQ(client->get_service_name(), "/ns/sub_ns/service");
}
{
ASSERT_THROW({
auto client = node->create_client<ListParameters>("invalid_service?");
}, rclcpp::exceptions::InvalidServiceNameError);
}
}

View File

@@ -60,7 +60,6 @@ TEST(TestDuration, operators) {
rclcpp::Duration time = rclcpp::Duration(0, 0);
rclcpp::Duration copy_constructor_duration(time);
rclcpp::Duration assignment_op_duration = rclcpp::Duration(1, 0);
(void)assignment_op_duration;
assignment_op_duration = time;
EXPECT_TRUE(time == copy_constructor_duration);
@@ -76,14 +75,6 @@ TEST(TestDuration, chrono_overloads) {
EXPECT_EQ(d1, d2);
EXPECT_EQ(d1, d3);
EXPECT_EQ(d2, d3);
// check non-nanosecond durations
std::chrono::milliseconds chrono_ms(100);
auto d4 = rclcpp::Duration(chrono_ms);
EXPECT_EQ(chrono_ms, d4.to_chrono<std::chrono::nanoseconds>());
std::chrono::duration<double, std::chrono::seconds::period> chrono_float_seconds(3.14);
auto d5 = rclcpp::Duration(chrono_float_seconds);
EXPECT_EQ(chrono_float_seconds, d5.to_chrono<decltype(chrono_float_seconds)>());
}
TEST(TestDuration, overflows) {

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.
#include <gtest/gtest.h>
#include "rclcpp/node_interfaces/interface_traits.hpp"
#include "rclcpp/node_interfaces/node_base.hpp"
#include "rclcpp/node.hpp"
class MyNode
{
public:
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> get_node_base_interface() const
{
return std::make_shared<rclcpp::node_interfaces::NodeBase>("my_node_name", "my_node_namespace", nullptr, rclcpp::NodeOptions());
}
};
class WrongNode
{
public:
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> not_get_node_base_interface()
{
return nullptr;
}
};
template<class T, typename std::enable_if<rclcpp::node_interfaces::has_node_base_interface<T>::value>::type* = nullptr>
void get_node_name(const T & nodelike) {
ASSERT_STREQ("my_node_name", nodelike.get_node_base_interface()->get_name());
}
TEST(TestInterfaceTraits, has_node_base_interface) {
ASSERT_TRUE(rclcpp::node_interfaces::has_node_base_interface<MyNode>::value);
ASSERT_FALSE(rclcpp::node_interfaces::has_node_base_interface<WrongNode>::value);
ASSERT_TRUE(rclcpp::node_interfaces::has_node_base_interface<rclcpp::Node>::value);
get_node_name(MyNode());
}

View File

@@ -14,13 +14,10 @@
#include <memory>
#include <string>
#include <utility>
#define RCLCPP_BUILDING_LIBRARY 1
#include "gtest/gtest.h"
#include "rclcpp/allocator/allocator_common.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/mapped_ring_buffer.hpp"
#include "rmw/types.h"
// Mock up publisher and subscription base to avoid needing an rmw impl.
@@ -53,14 +50,6 @@ public:
return false;
}
virtual
mapped_ring_buffer::MappedRingBufferBase::SharedPtr
make_mapped_ring_buffer(size_t size) const
{
(void)size;
return nullptr;
}
std::string mock_topic_name;
size_t mock_queue_size;
};
@@ -82,15 +71,6 @@ public:
allocator_ = std::make_shared<MessageAlloc>();
}
mapped_ring_buffer::MappedRingBufferBase::SharedPtr
make_mapped_ring_buffer(size_t size) const override
{
return mapped_ring_buffer::MappedRingBuffer<
T,
typename Publisher<T, Alloc>::MessageAlloc
>::make_shared(size, allocator_);
}
std::shared_ptr<MessageAlloc> get_allocator()
{
return allocator_;
@@ -129,9 +109,10 @@ public:
} // namespace mock
} // namespace rclcpp
// Prevent rclcpp/publisher_base.hpp and rclcpp/subscription.hpp from being imported.
#define RCLCPP__PUBLISHER_BASE_HPP_
#define RCLCPP__SUBSCRIPTION_BASE_HPP_
// Prevent rclcpp/publisher.hpp and rclcpp/subscription.hpp from being imported.
#define RCLCPP__PUBLISHER_HPP_
#define RCLCPP__SUBSCRIPTION_HPP_
#define RCLCPP_BUILDING_LIBRARY 1
// Force ipm to use our mock publisher class.
#define Publisher mock::Publisher
#define PublisherBase mock::PublisherBase
@@ -174,8 +155,10 @@ TEST(TestIntraProcessManager, nominal) {
s1->mock_topic_name = "nominal1";
s1->mock_queue_size = 10;
auto p1_id = ipm.add_publisher(p1);
auto p2_id = ipm.add_publisher(p2);
auto p1_id =
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p1);
auto p2_id =
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p2);
auto s1_id = ipm.add_subscription(s1);
auto ipm_msg = std::make_shared<rcl_interfaces::msg::IntraProcessMessage>();
@@ -186,14 +169,14 @@ TEST(TestIntraProcessManager, nominal) {
);
auto p1_m1_original_address = unique_msg.get();
auto p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
auto p1_m1_id = ipm.store_intra_process_message(p1_id, unique_msg);
ASSERT_EQ(nullptr, unique_msg);
ipm_msg->message_sequence = 43;
ipm_msg->publisher_id = 43;
unique_msg.reset(new rcl_interfaces::msg::IntraProcessMessage(*ipm_msg));
auto p2_m1_id = ipm.store_intra_process_message(p2_id, std::move(unique_msg));
auto p2_m1_id = ipm.store_intra_process_message(p2_id, unique_msg);
ASSERT_EQ(nullptr, unique_msg);
ipm.take_intra_process_message(p2_id, p2_m1_id, s1_id, unique_msg);
@@ -215,22 +198,26 @@ TEST(TestIntraProcessManager, nominal) {
ipm_msg->publisher_id = 44;
unique_msg.reset(new rcl_interfaces::msg::IntraProcessMessage(*ipm_msg));
ipm.store_intra_process_message(p1_id, std::move(unique_msg));
ipm.store_intra_process_message(p1_id, unique_msg);
ASSERT_EQ(nullptr, unique_msg);
ipm_msg->message_sequence = 45;
ipm_msg->publisher_id = 45;
unique_msg.reset(new rcl_interfaces::msg::IntraProcessMessage(*ipm_msg));
ipm.store_intra_process_message(p1_id, std::move(unique_msg));
ipm.store_intra_process_message(p1_id, unique_msg);
ASSERT_EQ(nullptr, unique_msg);
ipm_msg->message_sequence = 46;
ipm_msg->publisher_id = 46;
unique_msg.reset(new rcl_interfaces::msg::IntraProcessMessage(*ipm_msg));
ipm.store_intra_process_message(p1_id, std::move(unique_msg));
ASSERT_EQ(nullptr, unique_msg);
ipm.store_intra_process_message(p1_id, unique_msg);
ASSERT_NE(nullptr, unique_msg);
if (unique_msg) {
EXPECT_EQ(44ul, unique_msg->message_sequence);
EXPECT_EQ(44ul, unique_msg->publisher_id);
}
}
/*
@@ -253,7 +240,8 @@ TEST(TestIntraProcessManager, remove_publisher_before_trying_to_take) {
s1->mock_topic_name = "nominal1";
s1->mock_queue_size = 10;
auto p1_id = ipm.add_publisher(p1);
auto p1_id =
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p1);
auto s1_id = ipm.add_subscription(s1);
auto ipm_msg = std::make_shared<rcl_interfaces::msg::IntraProcessMessage>();
@@ -263,7 +251,7 @@ TEST(TestIntraProcessManager, remove_publisher_before_trying_to_take) {
new rcl_interfaces::msg::IntraProcessMessage(*ipm_msg)
);
auto p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
auto p1_m1_id = ipm.store_intra_process_message(p1_id, unique_msg);
ASSERT_EQ(nullptr, unique_msg);
ipm.remove_publisher(p1_id);
@@ -302,7 +290,8 @@ TEST(TestIntraProcessManager, removed_subscription_affects_take) {
s3->mock_topic_name = "nominal1";
s3->mock_queue_size = 10;
auto p1_id = ipm.add_publisher(p1);
auto p1_id =
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p1);
auto s1_id = ipm.add_subscription(s1);
auto s2_id = ipm.add_subscription(s2);
auto s3_id = ipm.add_subscription(s3);
@@ -315,7 +304,7 @@ TEST(TestIntraProcessManager, removed_subscription_affects_take) {
);
auto original_message_pointer = unique_msg.get();
auto p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
auto p1_m1_id = ipm.store_intra_process_message(p1_id, unique_msg);
ASSERT_EQ(nullptr, unique_msg);
ipm.take_intra_process_message(p1_id, p1_m1_id, s1_id, unique_msg);
@@ -372,7 +361,8 @@ TEST(TestIntraProcessManager, multiple_subscriptions_one_publisher) {
s3->mock_topic_name = "nominal1";
s3->mock_queue_size = 10;
auto p1_id = ipm.add_publisher(p1);
auto p1_id =
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p1);
auto s1_id = ipm.add_subscription(s1);
auto s2_id = ipm.add_subscription(s2);
auto s3_id = ipm.add_subscription(s3);
@@ -385,7 +375,7 @@ TEST(TestIntraProcessManager, multiple_subscriptions_one_publisher) {
);
auto original_message_pointer = unique_msg.get();
auto p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
auto p1_m1_id = ipm.store_intra_process_message(p1_id, unique_msg);
ASSERT_EQ(nullptr, unique_msg);
ipm.take_intra_process_message(p1_id, p1_m1_id, s1_id, unique_msg);
@@ -447,9 +437,12 @@ TEST(TestIntraProcessManager, multiple_publishers_one_subscription) {
s1->mock_topic_name = "nominal1";
s1->mock_queue_size = 10;
auto p1_id = ipm.add_publisher(p1);
auto p2_id = ipm.add_publisher(p2);
auto p3_id = ipm.add_publisher(p3);
auto p1_id =
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p1);
auto p2_id =
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p2);
auto p3_id =
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p3);
auto s1_id = ipm.add_subscription(s1);
auto ipm_msg = std::make_shared<rcl_interfaces::msg::IntraProcessMessage>();
@@ -461,7 +454,7 @@ TEST(TestIntraProcessManager, multiple_publishers_one_subscription) {
);
auto original_message_pointer1 = unique_msg.get();
auto p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
auto p1_m1_id = ipm.store_intra_process_message(p1_id, unique_msg);
ASSERT_EQ(nullptr, unique_msg);
// Second publish
@@ -470,7 +463,7 @@ TEST(TestIntraProcessManager, multiple_publishers_one_subscription) {
unique_msg.reset(new rcl_interfaces::msg::IntraProcessMessage(*ipm_msg));
auto original_message_pointer2 = unique_msg.get();
auto p2_m1_id = ipm.store_intra_process_message(p2_id, std::move(unique_msg));
auto p2_m1_id = ipm.store_intra_process_message(p2_id, unique_msg);
ASSERT_EQ(nullptr, unique_msg);
// Third publish
@@ -479,7 +472,7 @@ TEST(TestIntraProcessManager, multiple_publishers_one_subscription) {
unique_msg.reset(new rcl_interfaces::msg::IntraProcessMessage(*ipm_msg));
auto original_message_pointer3 = unique_msg.get();
auto p3_m1_id = ipm.store_intra_process_message(p3_id, std::move(unique_msg));
auto p3_m1_id = ipm.store_intra_process_message(p3_id, unique_msg);
ASSERT_EQ(nullptr, unique_msg);
// First take
@@ -552,9 +545,12 @@ TEST(TestIntraProcessManager, multiple_publishers_multiple_subscription) {
s3->mock_topic_name = "nominal1";
s3->mock_queue_size = 10;
auto p1_id = ipm.add_publisher(p1);
auto p2_id = ipm.add_publisher(p2);
auto p3_id = ipm.add_publisher(p3);
auto p1_id =
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p1);
auto p2_id =
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p2);
auto p3_id =
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p3);
auto s1_id = ipm.add_subscription(s1);
auto s2_id = ipm.add_subscription(s2);
auto s3_id = ipm.add_subscription(s3);
@@ -568,7 +564,7 @@ TEST(TestIntraProcessManager, multiple_publishers_multiple_subscription) {
);
auto original_message_pointer1 = unique_msg.get();
auto p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
auto p1_m1_id = ipm.store_intra_process_message(p1_id, unique_msg);
ASSERT_EQ(nullptr, unique_msg);
// Second publish
@@ -577,7 +573,7 @@ TEST(TestIntraProcessManager, multiple_publishers_multiple_subscription) {
unique_msg.reset(new rcl_interfaces::msg::IntraProcessMessage(*ipm_msg));
auto original_message_pointer2 = unique_msg.get();
auto p2_m1_id = ipm.store_intra_process_message(p2_id, std::move(unique_msg));
auto p2_m1_id = ipm.store_intra_process_message(p2_id, unique_msg);
ASSERT_EQ(nullptr, unique_msg);
// Third publish
@@ -586,7 +582,7 @@ TEST(TestIntraProcessManager, multiple_publishers_multiple_subscription) {
unique_msg.reset(new rcl_interfaces::msg::IntraProcessMessage(*ipm_msg));
auto original_message_pointer3 = unique_msg.get();
auto p3_m1_id = ipm.store_intra_process_message(p3_id, std::move(unique_msg));
auto p3_m1_id = ipm.store_intra_process_message(p3_id, unique_msg);
ASSERT_EQ(nullptr, unique_msg);
// First take
@@ -696,7 +692,8 @@ TEST(TestIntraProcessManager, ring_buffer_displacement) {
s1->mock_topic_name = "nominal1";
s1->mock_queue_size = 10;
auto p1_id = ipm.add_publisher(p1);
auto p1_id =
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p1);
auto s1_id = ipm.add_subscription(s1);
auto ipm_msg = std::make_shared<rcl_interfaces::msg::IntraProcessMessage>();
@@ -706,7 +703,8 @@ TEST(TestIntraProcessManager, ring_buffer_displacement) {
new rcl_interfaces::msg::IntraProcessMessage(*ipm_msg)
);
auto p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
auto original_message_pointer1 = unique_msg.get();
auto p1_m1_id = ipm.store_intra_process_message(p1_id, unique_msg);
ASSERT_EQ(nullptr, unique_msg);
ipm_msg->message_sequence = 43;
@@ -714,7 +712,7 @@ TEST(TestIntraProcessManager, ring_buffer_displacement) {
unique_msg.reset(new rcl_interfaces::msg::IntraProcessMessage(*ipm_msg));
auto original_message_pointer2 = unique_msg.get();
auto p1_m2_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
auto p1_m2_id = ipm.store_intra_process_message(p1_id, unique_msg);
ASSERT_EQ(nullptr, unique_msg);
ipm.take_intra_process_message(p1_id, p1_m2_id, s1_id, unique_msg);
@@ -730,8 +728,14 @@ TEST(TestIntraProcessManager, ring_buffer_displacement) {
ipm_msg->publisher_id = 44;
unique_msg.reset(new rcl_interfaces::msg::IntraProcessMessage(*ipm_msg));
ipm.store_intra_process_message(p1_id, std::move(unique_msg));
EXPECT_EQ(nullptr, unique_msg);
ipm.store_intra_process_message(p1_id, unique_msg);
EXPECT_NE(nullptr, unique_msg); // Should return the thing in the ring buffer it displaced.
if (unique_msg) {
// This should have been the first published message.
EXPECT_EQ(42ul, unique_msg->message_sequence);
EXPECT_EQ(42ul, unique_msg->publisher_id);
EXPECT_EQ(original_message_pointer1, unique_msg.get());
}
unique_msg.reset();
// Since it just got displaced it should no longer be there to take.
@@ -755,7 +759,8 @@ TEST(TestIntraProcessManager, subscription_creation_race_condition) {
p1->mock_topic_name = "nominal1";
p1->mock_queue_size = 2;
auto p1_id = ipm.add_publisher(p1);
auto p1_id =
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p1);
auto ipm_msg = std::make_shared<rcl_interfaces::msg::IntraProcessMessage>();
ipm_msg->message_sequence = 42;
@@ -764,7 +769,7 @@ TEST(TestIntraProcessManager, subscription_creation_race_condition) {
new rcl_interfaces::msg::IntraProcessMessage(*ipm_msg)
);
auto p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
auto p1_m1_id = ipm.store_intra_process_message(p1_id, unique_msg);
ASSERT_EQ(nullptr, unique_msg);
auto s1 = std::make_shared<rclcpp::mock::SubscriptionBase>();
@@ -803,7 +808,7 @@ TEST(TestIntraProcessManager, publisher_out_of_scope_take) {
p1->mock_topic_name = "nominal1";
p1->mock_queue_size = 2;
p1_id = ipm.add_publisher(p1);
p1_id = ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p1);
auto ipm_msg = std::make_shared<rcl_interfaces::msg::IntraProcessMessage>();
ipm_msg->message_sequence = 42;
@@ -812,7 +817,7 @@ TEST(TestIntraProcessManager, publisher_out_of_scope_take) {
new rcl_interfaces::msg::IntraProcessMessage(*ipm_msg)
);
p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
p1_m1_id = ipm.store_intra_process_message(p1_id, unique_msg);
ASSERT_EQ(nullptr, unique_msg);
// Explicitly remove publisher from ipm (emulate's publisher's destructor).
@@ -842,7 +847,7 @@ TEST(TestIntraProcessManager, publisher_out_of_scope_store) {
p1->mock_topic_name = "nominal1";
p1->mock_queue_size = 2;
p1_id = ipm.add_publisher(p1);
p1_id = ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p1);
}
auto ipm_msg = std::make_shared<rcl_interfaces::msg::IntraProcessMessage>();
@@ -852,6 +857,6 @@ TEST(TestIntraProcessManager, publisher_out_of_scope_store) {
new rcl_interfaces::msg::IntraProcessMessage(*ipm_msg)
);
EXPECT_THROW(ipm.store_intra_process_message(p1_id, std::move(unique_msg)), std::runtime_error);
EXPECT_THROW(ipm.store_intra_process_message(p1_id, unique_msg), std::runtime_error);
ASSERT_EQ(nullptr, unique_msg);
}

View File

@@ -21,9 +21,7 @@
#include "rclcpp/rclcpp.hpp"
TEST(test_local_parameters, set_parameter_if_not_set) {
auto node = rclcpp::Node::make_shared(
"test_local_parameters_set_parameter_if_not_set",
rclcpp::NodeOptions().allow_undeclared_parameters(true));
auto node = rclcpp::Node::make_shared("test_local_parameters_set_parameter_if_not_set");
{
// try to set a map of parameters
@@ -31,19 +29,7 @@ TEST(test_local_parameters, set_parameter_if_not_set) {
{"x", 0.5},
{"y", 1.0},
};
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
node->set_parameters_if_not_set("bar", bar_map);
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
double bar_x_value;
ASSERT_TRUE(node->get_parameter("bar.x", bar_x_value));
EXPECT_EQ(bar_x_value, 0.5);
@@ -65,20 +51,8 @@ TEST(test_local_parameters, set_parameter_if_not_set) {
{
// set parameters for a map with different types, then try to get them back as a map
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
node->set_parameter_if_not_set("baz.x", 1.0);
node->set_parameter_if_not_set("baz.y", "hello");
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
std::map<std::string, double> baz_map;
EXPECT_THROW(node->get_parameters("baz", baz_map), rclcpp::ParameterTypeException);
}

View File

@@ -12,13 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <memory>
#include <utility>
#include "gtest/gtest.h"
#include <gtest/gtest.h>
#define RCLCPP_BUILDING_LIBRARY 1 // Prevent including unavailable symbols
#include "rclcpp/mapped_ring_buffer.hpp"
#include <rclcpp/mapped_ring_buffer.hpp>
#include <memory>
/*
Tests get_copy and pop on an empty mrb.
@@ -29,90 +28,60 @@ TEST(TestMappedRingBuffer, empty) {
// Getting or popping an empty buffer should result in a nullptr.
rclcpp::mapped_ring_buffer::MappedRingBuffer<char> mrb(1);
std::unique_ptr<char> unique;
mrb.get(1, unique);
EXPECT_EQ(nullptr, unique);
std::unique_ptr<char> actual;
mrb.get_copy_at_key(1, actual);
EXPECT_EQ(nullptr, actual);
mrb.pop(1, unique);
EXPECT_EQ(nullptr, unique);
std::shared_ptr<const char> shared;
mrb.get(1, shared);
EXPECT_EQ(nullptr, shared);
mrb.pop(1, shared);
EXPECT_EQ(nullptr, shared);
}
/*
Tests push_and_replace with a temporary object, and using
get and pop methods with shared_ptr signature.
*/
TEST(TestMappedRingBuffer, temporary_l_value_with_shared_get_pop) {
rclcpp::mapped_ring_buffer::MappedRingBuffer<char> mrb(2);
// Pass in value with temporary object
mrb.push_and_replace(1, std::shared_ptr<const char>(new char('a')));
std::shared_ptr<const char> actual;
mrb.get(1, actual);
EXPECT_EQ('a', *actual);
mrb.pop(1, actual);
EXPECT_EQ('a', *actual);
mrb.get(1, actual);
mrb.pop_at_key(1, actual);
EXPECT_EQ(nullptr, actual);
}
/*
Tests push_and_replace with a temporary object, and using
get and pop methods with unique_ptr signature.
Tests push_and_replace with a temporary object.
*/
TEST(TestMappedRingBuffer, temporary_l_value_with_unique_get_pop) {
TEST(TestMappedRingBuffer, temporary_l_value) {
rclcpp::mapped_ring_buffer::MappedRingBuffer<char> mrb(2);
// Pass in value with temporary object
mrb.push_and_replace(1, std::shared_ptr<const char>(new char('a')));
mrb.push_and_replace(1, std::unique_ptr<char>(new char('a')));
std::unique_ptr<char> actual;
mrb.get(1, actual);
mrb.get_copy_at_key(1, actual);
EXPECT_EQ('a', *actual);
mrb.pop(1, actual);
mrb.pop_at_key(1, actual);
EXPECT_EQ('a', *actual);
mrb.get(1, actual);
mrb.get_copy_at_key(1, actual);
EXPECT_EQ(nullptr, actual);
}
/*
Tests normal usage of the mrb.
Using shared push_and_replace, get and pop methods.
*/
TEST(TestMappedRingBuffer, nominal_push_shared_get_pop_shared) {
TEST(TestMappedRingBuffer, nominal) {
rclcpp::mapped_ring_buffer::MappedRingBuffer<char> mrb(2);
std::shared_ptr<const char> expected(new char('a'));
std::unique_ptr<char> expected(new char('a'));
// Store expected value's address for later comparison.
char * expected_orig = expected.get();
EXPECT_FALSE(mrb.push_and_replace(1, expected));
EXPECT_EQ(2, expected.use_count());
std::shared_ptr<const char> actual;
mrb.get(1, actual);
std::unique_ptr<char> actual;
mrb.get_copy_at_key(1, actual);
EXPECT_NE(nullptr, actual);
if (actual) {
EXPECT_EQ('a', *actual);
}
EXPECT_EQ(expected, actual);
EXPECT_EQ(3, actual.use_count());
EXPECT_NE(expected_orig, actual.get());
mrb.pop(1, actual);
EXPECT_EQ(expected, actual);
mrb.pop_at_key(1, actual);
EXPECT_NE(nullptr, actual);
if (actual) {
EXPECT_EQ('a', *actual);
}
expected.reset();
EXPECT_TRUE(actual.unique());
EXPECT_EQ(expected_orig, actual.get());
mrb.get(1, actual);
mrb.get_copy_at_key(1, actual);
EXPECT_EQ(nullptr, actual);
expected.reset(new char('a'));
@@ -124,16 +93,16 @@ TEST(TestMappedRingBuffer, nominal_push_shared_get_pop_shared) {
expected.reset(new char('c'));
EXPECT_TRUE(mrb.push_and_replace(3, expected));
mrb.get(1, actual);
mrb.get_copy_at_key(1, actual);
EXPECT_EQ(nullptr, actual);
mrb.get(2, actual);
mrb.get_copy_at_key(2, actual);
EXPECT_NE(nullptr, actual);
if (actual) {
EXPECT_EQ('b', *actual);
}
mrb.get(3, actual);
mrb.get_copy_at_key(3, actual);
EXPECT_NE(nullptr, actual);
if (actual) {
EXPECT_EQ('c', *actual);
@@ -141,167 +110,40 @@ TEST(TestMappedRingBuffer, nominal_push_shared_get_pop_shared) {
}
/*
Tests normal usage of the mrb.
Using shared push_and_replace, unique get and pop methods.
Tests get_ownership on a normal mrb.
*/
TEST(TestMappedRingBuffer, nominal_push_shared_get_pop_unique) {
rclcpp::mapped_ring_buffer::MappedRingBuffer<char> mrb(2);
std::shared_ptr<const char> expected(new char('a'));
const char * expected_orig = expected.get();
EXPECT_FALSE(mrb.push_and_replace(1, expected));
EXPECT_EQ(2, expected.use_count());
std::unique_ptr<char> actual;
mrb.get(1, actual);
EXPECT_NE(nullptr, actual);
if (actual) {
EXPECT_EQ('a', *actual);
}
EXPECT_NE(expected_orig, actual.get());
mrb.pop(1, actual);
EXPECT_NE(expected_orig, actual.get());
if (actual) {
EXPECT_EQ('a', *actual);
}
mrb.get(1, actual);
EXPECT_EQ(nullptr, actual);
EXPECT_FALSE(mrb.push_and_replace(1, expected));
expected.reset();
mrb.pop(1, actual);
EXPECT_NE(expected_orig, actual.get());
if (actual) {
EXPECT_EQ('a', *actual);
}
mrb.get(1, actual);
EXPECT_EQ(nullptr, actual);
expected.reset(new char('a'));
EXPECT_FALSE(mrb.push_and_replace(1, expected));
expected.reset(new char('b'));
EXPECT_FALSE(mrb.push_and_replace(2, expected));
expected.reset(new char('c'));
EXPECT_TRUE(mrb.push_and_replace(3, expected));
mrb.get(1, actual);
EXPECT_EQ(nullptr, actual);
mrb.get(2, actual);
EXPECT_NE(nullptr, actual);
if (actual) {
EXPECT_EQ('b', *actual);
}
mrb.get(3, actual);
EXPECT_NE(nullptr, actual);
if (actual) {
EXPECT_EQ('c', *actual);
}
}
/*
Tests normal usage of the mrb.
Using unique push_and_replace, get and pop methods.
*/
TEST(TestMappedRingBuffer, nominal_push_unique_get_pop_unique) {
TEST(TestMappedRingBuffer, get_ownership) {
rclcpp::mapped_ring_buffer::MappedRingBuffer<char> mrb(2);
std::unique_ptr<char> expected(new char('a'));
const char * expected_orig = expected.get();
// Store expected value's address for later comparison.
char * expected_orig = expected.get();
EXPECT_FALSE(mrb.push_and_replace(1, std::move(expected)));
EXPECT_FALSE(mrb.push_and_replace(1, expected));
std::unique_ptr<char> actual;
mrb.get(1, actual);
mrb.get_copy_at_key(1, actual);
EXPECT_NE(nullptr, actual);
if (actual) {
EXPECT_EQ('a', *actual);
}
EXPECT_NE(expected_orig, actual.get());
mrb.pop(1, actual);
if (actual) {
EXPECT_EQ('a', *actual);
}
EXPECT_EQ(expected_orig, actual.get());
mrb.get(1, actual);
EXPECT_EQ(nullptr, actual);
expected.reset(new char('a'));
EXPECT_FALSE(mrb.push_and_replace(1, std::move(expected)));
expected.reset(new char('b'));
EXPECT_FALSE(mrb.push_and_replace(2, std::move(expected)));
expected.reset(new char('c'));
EXPECT_TRUE(mrb.push_and_replace(3, std::move(expected)));
mrb.get(1, actual);
EXPECT_EQ(nullptr, actual);
mrb.get(2, actual);
EXPECT_NE(nullptr, actual);
if (actual) {
EXPECT_EQ('b', *actual);
}
mrb.get(3, actual);
EXPECT_NE(nullptr, actual);
if (actual) {
EXPECT_EQ('c', *actual);
}
}
/*
Tests normal usage of the mrb.
Using unique push_and_replace, shared get and pop methods.
*/
TEST(TestMappedRingBuffer, nominal_push_unique_get_pop_shared) {
rclcpp::mapped_ring_buffer::MappedRingBuffer<char> mrb(2);
std::unique_ptr<char> expected(new char('a'));
const char * expected_orig = expected.get();
EXPECT_FALSE(mrb.push_and_replace(1, std::move(expected)));
std::shared_ptr<const char> actual;
mrb.get(1, actual);
mrb.get_ownership_at_key(1, actual);
EXPECT_NE(nullptr, actual);
if (actual) {
EXPECT_EQ('a', *actual);
}
EXPECT_EQ(expected_orig, actual.get());
mrb.pop(1, actual);
if (actual) {
EXPECT_EQ('a', *actual);
}
EXPECT_EQ(expected_orig, actual.get());
mrb.get(1, actual);
EXPECT_EQ(nullptr, actual);
expected.reset(new char('a'));
EXPECT_FALSE(mrb.push_and_replace(1, std::move(expected)));
expected.reset(new char('b'));
EXPECT_FALSE(mrb.push_and_replace(2, std::move(expected)));
expected.reset(new char('c'));
EXPECT_TRUE(mrb.push_and_replace(3, std::move(expected)));
mrb.get(1, actual);
EXPECT_EQ(nullptr, actual);
mrb.get(2, actual);
mrb.pop_at_key(1, actual);
EXPECT_NE(nullptr, actual);
if (actual) {
EXPECT_EQ('b', *actual);
EXPECT_EQ('a', *actual); // The value should be the same.
}
EXPECT_NE(expected_orig, actual.get()); // Even though we pop'ed, we didn't get the original.
mrb.get(3, actual);
EXPECT_NE(nullptr, actual);
if (actual) {
EXPECT_EQ('c', *actual);
}
mrb.get_copy_at_key(1, actual);
EXPECT_EQ(nullptr, actual);
}
/*
@@ -310,23 +152,22 @@ TEST(TestMappedRingBuffer, nominal_push_unique_get_pop_shared) {
TEST(TestMappedRingBuffer, non_unique_keys) {
rclcpp::mapped_ring_buffer::MappedRingBuffer<char> mrb(2);
std::shared_ptr<const char> input(new char('a'));
std::unique_ptr<char> input(new char('a'));
mrb.push_and_replace(1, input);
input.reset(new char('b'));
// Different value, same key.
mrb.push_and_replace(1, input);
input.reset();
std::unique_ptr<char> actual;
mrb.pop(1, actual);
mrb.pop_at_key(1, actual);
EXPECT_NE(nullptr, actual);
if (actual) {
EXPECT_EQ('a', *actual);
}
actual = nullptr;
mrb.pop(1, actual);
mrb.pop_at_key(1, actual);
EXPECT_NE(nullptr, actual);
if (actual) {
EXPECT_EQ('b', *actual);

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,6 @@
#include "rclcpp/exceptions.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/node_options.hpp"
#include "rclcpp/rclcpp.hpp"
class TestNodeWithGlobalArgs : public ::testing::Test
@@ -34,26 +33,32 @@ protected:
};
TEST_F(TestNodeWithGlobalArgs, local_arguments_before_global) {
auto options = rclcpp::NodeOptions()
.arguments({"__node:=local_arguments_test"});
auto node = rclcpp::Node::make_shared("orig_name", options);
auto context = rclcpp::contexts::default_context::get_global_default_context();
const std::vector<std::string> arguments = {"__node:=local_arguments_test"};
const std::vector<rclcpp::Parameter> initial_values = {};
const bool use_global_arguments = true;
const bool use_intra_process = false;
auto node = rclcpp::Node::make_shared(
"orig_name", "", context, arguments, initial_values, use_global_arguments, use_intra_process);
EXPECT_STREQ("local_arguments_test", node->get_name());
}
TEST_F(TestNodeWithGlobalArgs, use_or_ignore_global_arguments) {
{ // Don't use global args
auto options = rclcpp::NodeOptions()
.use_global_arguments(false);
auto context = rclcpp::contexts::default_context::get_global_default_context();
const std::vector<std::string> arguments = {};
const std::vector<rclcpp::Parameter> initial_values = {};
const bool use_intra_process = false;
auto node = rclcpp::Node::make_shared("orig_name", options);
{ // Don't use global args
const bool use_global_arguments = false;
auto node = rclcpp::Node::make_shared(
"orig_name", "", context, arguments, initial_values, use_global_arguments, use_intra_process);
EXPECT_STREQ("orig_name", node->get_name());
}
{ // Do use global args
auto options = rclcpp::NodeOptions()
.use_global_arguments(true);
auto node = rclcpp::Node::make_shared("orig_name", options);
const bool use_global_arguments = true;
auto node = rclcpp::Node::make_shared(
"orig_name", "", context, arguments, initial_values, use_global_arguments, use_intra_process);
EXPECT_STREQ("global_node_name", node->get_name());
}
}

View File

@@ -0,0 +1,117 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <string>
#include <memory>
#include <vector>
#include "rclcpp/node.hpp"
#include "rclcpp/rclcpp.hpp"
class TestNodeWithInitialValues : public ::testing::Test
{
protected:
static void SetUpTestCase()
{
rclcpp::init(0, NULL);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
};
TEST_F(TestNodeWithInitialValues, no_initial_values) {
auto context = rclcpp::contexts::default_context::get_global_default_context();
const std::vector<std::string> arguments = {};
const std::vector<rclcpp::Parameter> initial_values = {};
const bool use_global_arguments = false;
const bool use_intra_process = false;
auto node = rclcpp::Node::make_shared(
"node_name", "", context, arguments, initial_values, use_global_arguments, use_intra_process);
auto list_params_result = node->list_parameters({}, 0);
// Has use_sim_time parameter
EXPECT_EQ(1u, list_params_result.names.size());
}
TEST_F(TestNodeWithInitialValues, multiple_undeclared_initial_values) {
auto context = rclcpp::contexts::default_context::get_global_default_context();
const std::vector<std::string> arguments = {};
const std::vector<rclcpp::Parameter> initial_values = {
rclcpp::Parameter("foo", true),
rclcpp::Parameter("bar", "hello world"),
rclcpp::Parameter("baz", std::vector<double>{3.14, 2.718})
};
const bool use_global_arguments = false;
const bool use_intra_process = false;
auto node = rclcpp::Node::make_shared(
"node_name", "", context, arguments, initial_values, use_global_arguments, use_intra_process);
auto list_params_result = node->list_parameters({}, 0);
// Has use_sim_time parameter
EXPECT_EQ(1u, list_params_result.names.size());
}
TEST_F(TestNodeWithInitialValues, multiple_declared_initial_values) {
auto context = rclcpp::contexts::default_context::get_global_default_context();
const std::vector<std::string> arguments = {};
const std::vector<rclcpp::Parameter> initial_values = {
rclcpp::Parameter("foo", true),
rclcpp::Parameter("bar", "hello world"),
rclcpp::Parameter("baz", std::vector<double>{3.14, 2.718})
};
const bool use_global_arguments = false;
const bool use_intra_process = false;
auto node = rclcpp::Node::make_shared(
"node_name", "", context, arguments, initial_values, use_global_arguments, use_intra_process);
node->declare_parameter("foo");
node->declare_parameter("bar");
node->declare_parameter("baz");
auto list_params_result = node->list_parameters({}, 0);
EXPECT_TRUE(node->get_parameter("foo").get_value<bool>());
EXPECT_STREQ("hello world", node->get_parameter("bar").get_value<std::string>().c_str());
std::vector<double> double_array = node->get_parameter("baz").get_value<std::vector<double>>();
ASSERT_EQ(2u, double_array.size());
EXPECT_DOUBLE_EQ(3.14, double_array.at(0));
EXPECT_DOUBLE_EQ(2.718, double_array.at(1));
}
TEST_F(TestNodeWithInitialValues, multiple_undeclared_initial_values_allowed) {
auto context = rclcpp::contexts::default_context::get_global_default_context();
const std::vector<std::string> arguments = {};
const std::vector<rclcpp::Parameter> initial_values = {
rclcpp::Parameter("foo", true),
rclcpp::Parameter("bar", "hello world"),
rclcpp::Parameter("baz", std::vector<double>{3.14, 2.718})
};
const bool use_global_arguments = false;
const bool use_intra_process = false;
const bool start_param_services = true;
const bool allow_undeclared_params = true;
auto node = rclcpp::Node::make_shared(
"node_name", "", context, arguments, initial_values, use_global_arguments, use_intra_process,
start_param_services, allow_undeclared_params);
auto list_params_result = node->list_parameters({}, 0);
EXPECT_TRUE(node->get_parameter("foo").get_value<bool>());
EXPECT_STREQ("hello world", node->get_parameter("bar").get_value<std::string>().c_str());
std::vector<double> double_array = node->get_parameter("baz").get_value<std::vector<double>>();
ASSERT_EQ(2u, double_array.size());
EXPECT_DOUBLE_EQ(3.14, double_array.at(0));
EXPECT_DOUBLE_EQ(2.718, double_array.at(1));
}

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