Compare commits
84 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
403aac9662 | ||
|
|
e8cf066d7d | ||
|
|
c4c39a2069 | ||
|
|
b3ecbd5ff7 | ||
|
|
052936980e | ||
|
|
6e133c2ad7 | ||
|
|
1f0f8f6176 | ||
|
|
ab2484295a | ||
|
|
c214ddc57b | ||
|
|
d27ca8ee85 | ||
|
|
342f225053 | ||
|
|
3c198de5b2 | ||
|
|
8906c9eb7f | ||
|
|
9e98aa70d3 | ||
|
|
6471043a0b | ||
|
|
f8bba370dc | ||
|
|
d5040ae304 | ||
|
|
3e5b6a47ea | ||
|
|
8c3fbce10d | ||
|
|
fb6ab9ef70 | ||
|
|
7629f5b6d9 | ||
|
|
7cb2ececcb | ||
|
|
0f4fc08a93 | ||
|
|
82f6dfa6de | ||
|
|
fadd923aa0 | ||
|
|
f954ce5145 | ||
|
|
895145cfc9 | ||
|
|
3cdb3cb1bf | ||
|
|
5d5d3ce09d | ||
|
|
839ad201ac | ||
|
|
f3b0aa170c | ||
|
|
6e76503d9a | ||
|
|
b4629bf889 | ||
|
|
3f31ad0f55 | ||
|
|
25eeffdfcc | ||
|
|
3293603396 | ||
|
|
50ec1e568a | ||
|
|
607e290732 | ||
|
|
47ce42bc3f | ||
|
|
d2f052ee3d | ||
|
|
b86127d721 | ||
|
|
5cb6a6eeb5 | ||
|
|
f41e33c2a7 | ||
|
|
10c34ee9e5 | ||
|
|
6d3cbd39d1 | ||
|
|
bfee90ab7a | ||
|
|
1927f7e40e | ||
|
|
f73d80e79c | ||
|
|
e2e35570d5 | ||
|
|
5c395d6651 | ||
|
|
24080a458d | ||
|
|
8ff51833ad | ||
|
|
347f8d0b1d | ||
|
|
ecc95009f1 | ||
|
|
d2b2f9124e | ||
|
|
ca01555936 | ||
|
|
0723a0a6fc | ||
|
|
8553fbea7f | ||
|
|
131a11bba5 | ||
|
|
29308dc8bc | ||
|
|
06275105fc | ||
|
|
30df5cdf36 | ||
|
|
1a662d46fb | ||
|
|
4467ce9913 | ||
|
|
005131dba8 | ||
|
|
05c19028f4 | ||
|
|
a8f4d391f2 | ||
|
|
0682ceb3e1 | ||
|
|
2152e0574b | ||
|
|
1081e75079 | ||
|
|
b17bbf31b3 | ||
|
|
ef41059a75 | ||
|
|
cfeb6a6360 | ||
|
|
c769b1b030 | ||
|
|
385cccc2cc | ||
|
|
d399fef9c6 | ||
|
|
ecf35114b6 | ||
|
|
7ed130cf7a | ||
|
|
59d59b0c18 | ||
|
|
a8a0788f81 | ||
|
|
e9101b49cd | ||
|
|
078d5ff662 | ||
|
|
dc05a2e755 | ||
|
|
98f610c114 |
@@ -2,6 +2,123 @@
|
||||
Changelog for package rclcpp
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
0.7.16 (2021-05-21)
|
||||
-------------------
|
||||
* Fix documented example in create_publisher. (`#1558 <https://github.com/ros2/rclcpp/issues/1558>`_) (`#1560 <https://github.com/ros2/rclcpp/issues/1560>`_)
|
||||
* Fix NodeOptions copy constructor. (`#1376 <https://github.com/ros2/rclcpp/issues/1376>`_) (`#1466 <https://github.com/ros2/rclcpp/issues/1466>`_)
|
||||
* Contributors: Ivan Santiago Paunovic, Jacob Perron
|
||||
|
||||
0.7.15 (2020-11-24)
|
||||
-------------------
|
||||
* Fix implementation of NodeOptions::use_global_arguments(). (`#1176 <https://github.com/ros2/rclcpp/issues/1176>`_) (`#1206 <https://github.com/ros2/rclcpp/issues/1206>`_)
|
||||
* Fix conversion of negative durations to messages. (`#1188 <https://github.com/ros2/rclcpp/issues/1188>`_) (`#1207 <https://github.com/ros2/rclcpp/issues/1207>`_)
|
||||
* Type conversions fixes. (`#901 <https://github.com/ros2/rclcpp/issues/901>`_) (`#1209 <https://github.com/ros2/rclcpp/issues/1209>`_)
|
||||
* Add operator!= for duration (`#1236 <https://github.com/ros2/rclcpp/issues/1236>`_) (`#1277 <https://github.com/ros2/rclcpp/issues/1277>`_)
|
||||
* Contributors: Ivan Santiago Paunovic, Michel Hidalgo, Monika Idzik
|
||||
|
||||
0.7.14 (2020-07-10)
|
||||
-------------------
|
||||
* Fixed doxygen warnings. (`#1208 <https://github.com/ros2/rclcpp/issues/1208>`_)
|
||||
* Check if context is valid when looping in spin_some. (`#1167 <https://github.com/ros2/rclcpp/issues/1167>`_)
|
||||
* Fix spin_until_future_complete: check spinning value. (`#1023 <https://github.com/ros2/rclcpp/issues/1023>`_)
|
||||
* Fix exception on rcl_clock_init. (`#1195 <https://github.com/ros2/rclcpp/issues/1195>`_)
|
||||
* Fix lock-order-inversion (potential deadlock). (`#1138 <https://github.com/ros2/rclcpp/issues/1138>`_)
|
||||
* Contributors: Alejandro Hernández Cordero, DongheeYe, Ivan Santiago Paunovic, tomoya
|
||||
|
||||
0.7.13 (2020-03-12)
|
||||
-------------------
|
||||
* Don't specify calling convention in std::_Binder template. (`#1015 <https://github.com/ros2/rclcpp/issues/1015>`_)
|
||||
* Contributors: Jacob Perron, Sean Kelly
|
||||
|
||||
0.7.12 (2019-12-05)
|
||||
-------------------
|
||||
|
||||
0.7.11 (2019-10-11)
|
||||
-------------------
|
||||
* Fix `get_node_*_interface` functions taking a pointer (`#870 <https://github.com/ros2/rclcpp/pull/870>`_).
|
||||
* Fix hang with timers in `MultiThreadedExecutor` (`#869 <https://github.com/ros2/rclcpp/pull/869>`_).
|
||||
* Contributors: Todd Malsbary, ivanpauno
|
||||
|
||||
0.7.10 (2019-09-23)
|
||||
-------------------
|
||||
|
||||
0.7.9 (2019-09-20)
|
||||
------------------
|
||||
* add mutex in add/remove_node and wait_for_work to protect concurrent use/change of memory_strategy\_ (`#837 <https://github.com/ros2/rclcpp/issues/837>`_) (`#857 <https://github.com/ros2/rclcpp/issues/857>`_)
|
||||
* Contributors: Zachary Michaels
|
||||
|
||||
0.7.8 (2019-09-06)
|
||||
------------------
|
||||
|
||||
0.7.7 (2019-07-31)
|
||||
------------------
|
||||
* Enabled the creation of a parameter YAML file which is applied to each node. (`#805 <https://github.com/ros2/rclcpp/issues/805>`_)
|
||||
* Fixed a signed/unsigned integer comparison compiler warning. (`#804 <https://github.com/ros2/rclcpp/issues/804>`_)
|
||||
* Changed the QoS profile used when subscribing to parameter events to match the publishing side, i.e. ``rmw_qos_profile_parameter_events``. (`#798 <https://github.com/ros2/rclcpp/issues/798>`_)
|
||||
* Changed the logic in TimeSource to ignore use_sim_time parameter events coming from other nodes. (`#803 <https://github.com/ros2/rclcpp/issues/803>`_)
|
||||
* Added missing default values in the NodeParametersInterface. (`#794 <https://github.com/ros2/rclcpp/issues/794>`_)
|
||||
* Added support for const member callback functions. (`#763 <https://github.com/ros2/rclcpp/issues/763>`_)
|
||||
* Contributors: Esteve Fernandez, Gonzo, Karsten Knese, Michel Hidalgo, Scott K Logan
|
||||
|
||||
0.7.6 (2019-06-12)
|
||||
------------------
|
||||
* Ignore parameters overrides in set parameter methods when allowing undeclared parameters (`#756 <https://github.com/ros2/rclcpp/issues/756>`_)
|
||||
* Add rclcpp::create_timer() (`#757 <https://github.com/ros2/rclcpp/issues/757>`_)
|
||||
* checking origin of intra-process msg before taking them (`#753 <https://github.com/ros2/rclcpp/issues/753>`_)
|
||||
* Contributors: Alberto Soragna, Shane Loretz, ivanpauno
|
||||
|
||||
0.7.5 (2019-05-30)
|
||||
------------------
|
||||
* Avoid 'Intra process message no longer being stored when trying to handle it' warning (`#749 <https://github.com/ros2/rclcpp/issues/749>`_)
|
||||
* Contributors: ivanpauno
|
||||
|
||||
0.7.4 (2019-05-29)
|
||||
------------------
|
||||
* Rename parameter options (`#745 <https://github.com/ros2/rclcpp/issues/745>`_)
|
||||
* Bionic use of strerror_r (`#742 <https://github.com/ros2/rclcpp/issues/742>`_)
|
||||
* Enforce parameter ranges (`#735 <https://github.com/ros2/rclcpp/issues/735>`_)
|
||||
* removed not used parameter client (`#740 <https://github.com/ros2/rclcpp/issues/740>`_)
|
||||
* ensure removal of guard conditions of expired nodes from memory strategy (`#741 <https://github.com/ros2/rclcpp/issues/741>`_)
|
||||
* Fix typo in log warning message (`#737 <https://github.com/ros2/rclcpp/issues/737>`_)
|
||||
* Throw nice errors when creating a publisher with intraprocess communication and incompatible qos policy (`#729 <https://github.com/ros2/rclcpp/issues/729>`_)
|
||||
* Contributors: Alberto Soragna, Dirk Thomas, Jacob Perron, William Woodall, ivanpauno, roderick-koehle
|
||||
|
||||
0.7.3 (2019-05-20)
|
||||
------------------
|
||||
* Fixed misspelling, volitile -> volatile (`#724 <https://github.com/ros2/rclcpp/issues/724>`_), and then fixed that since it is a C++ keyword to be ``durability_volatile`` (`#725 <https://github.com/ros2/rclcpp/issues/725>`_)
|
||||
* Fixed a clang warning (`#723 <https://github.com/ros2/rclcpp/issues/723>`_)
|
||||
* Added ``on_parameter_event`` static method to the ``AsyncParametersClient`` (`#688 <https://github.com/ros2/rclcpp/issues/688>`_)
|
||||
* Added a guard against ``ParameterNotDeclaredException`` throwing from within the parameter service callbacks. (`#718 <https://github.com/ros2/rclcpp/issues/718>`_)
|
||||
* Added missing template functionality to lifecycle_node. (`#707 <https://github.com/ros2/rclcpp/issues/707>`_)
|
||||
* Fixed heap-use-after-free and memory leaks reported from ``test_node.cpp`` (`#719 <https://github.com/ros2/rclcpp/issues/719>`_)
|
||||
* Contributors: Alberto Soragna, Dirk Thomas, Emerson Knapp, Jacob Perron, Michael Jeronimo, Prajakta Gokhale
|
||||
|
||||
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>`_)
|
||||
|
||||
@@ -19,7 +19,11 @@ if(NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
endif()
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(-Wall -Wextra -Wpedantic)
|
||||
# About -Wno-sign-conversion: With Clang, -Wconversion implies -Wsign-conversion. There are a number of
|
||||
# implicit sign conversions in rclcpp and gtest.cc, see https://ci.ros2.org/job/ci_osx/9265/.
|
||||
# Hence disabling -Wsign-conversion for now until all those have eventually been fixed.
|
||||
# (from https://github.com/ros2/rclcpp/pull/1188#issuecomment-650229140)
|
||||
add_compile_options(-Wall -Wextra -Wconversion -Wno-sign-conversion -Wpedantic)
|
||||
endif()
|
||||
|
||||
include_directories(include)
|
||||
@@ -64,10 +68,12 @@ set(${PROJECT_NAME}_SRCS
|
||||
src/rclcpp/parameter_events_filter.cpp
|
||||
src/rclcpp/parameter_map.cpp
|
||||
src/rclcpp/parameter_service.cpp
|
||||
src/rclcpp/publisher.cpp
|
||||
src/rclcpp/publisher_base.cpp
|
||||
src/rclcpp/qos.cpp
|
||||
src/rclcpp/qos_event.cpp
|
||||
src/rclcpp/service.cpp
|
||||
src/rclcpp/signal_handler.cpp
|
||||
src/rclcpp/subscription.cpp
|
||||
src/rclcpp/subscription_base.cpp
|
||||
src/rclcpp/time.cpp
|
||||
src/rclcpp/time_source.cpp
|
||||
src/rclcpp/timer.cpp
|
||||
@@ -141,6 +147,8 @@ 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
|
||||
@@ -151,6 +159,18 @@ if(BUILD_TESTING)
|
||||
)
|
||||
target_link_libraries(test_client ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_create_timer test/test_create_timer.cpp)
|
||||
if(TARGET test_create_timer)
|
||||
ament_target_dependencies(test_create_timer
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rcl"
|
||||
"rosidl_generator_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
)
|
||||
target_link_libraries(test_create_timer ${PROJECT_NAME})
|
||||
target_include_directories(test_create_timer PRIVATE test/)
|
||||
endif()
|
||||
ament_add_gtest(test_expand_topic_or_service_name test/test_expand_topic_or_service_name.cpp)
|
||||
if(TARGET test_expand_topic_or_service_name)
|
||||
ament_target_dependencies(test_expand_topic_or_service_name
|
||||
@@ -200,6 +220,34 @@ if(BUILD_TESTING)
|
||||
)
|
||||
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
|
||||
@@ -210,6 +258,13 @@ if(BUILD_TESTING)
|
||||
)
|
||||
target_link_libraries(test_node_global_args ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_parameter_client test/test_parameter_client.cpp)
|
||||
if(TARGET test_parameter_client)
|
||||
ament_target_dependencies(test_parameter_client
|
||||
"rcl_interfaces"
|
||||
)
|
||||
target_link_libraries(test_parameter_client ${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
|
||||
@@ -244,15 +299,6 @@ if(BUILD_TESTING)
|
||||
)
|
||||
target_link_libraries(test_publisher ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_pub_sub_option_interface test/test_pub_sub_option_interface.cpp)
|
||||
if(TARGET test_pub_sub_option_interface)
|
||||
ament_target_dependencies(test_pub_sub_option_interface
|
||||
test_msgs
|
||||
)
|
||||
target_link_libraries(test_pub_sub_option_interface
|
||||
${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
|
||||
|
||||
56
rclcpp/cmake/rclcpp_add_build_failure_test.cmake
Normal file
56
rclcpp/cmake/rclcpp_add_build_failure_test.cmake
Normal file
@@ -0,0 +1,56 @@
|
||||
# Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
#
|
||||
# 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()
|
||||
@@ -65,7 +65,8 @@ 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)
|
||||
{
|
||||
@@ -83,7 +84,8 @@ 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)
|
||||
{
|
||||
|
||||
@@ -36,6 +36,7 @@ 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>)>;
|
||||
@@ -154,7 +155,6 @@ 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,30 +177,50 @@ public:
|
||||
}
|
||||
|
||||
void dispatch_intra_process(
|
||||
MessageUniquePtr & message, const rmw_message_info_t & message_info)
|
||||
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)
|
||||
{
|
||||
(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_;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/client.hpp"
|
||||
#include "rclcpp/publisher.hpp"
|
||||
#include "rclcpp/service.hpp"
|
||||
#include "rclcpp/subscription.hpp"
|
||||
#include "rclcpp/timer.hpp"
|
||||
@@ -92,6 +93,10 @@ 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);
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
#define RCLCPP__CLOCK_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/time.hpp"
|
||||
@@ -35,13 +32,17 @@ 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(
|
||||
std::function<void()> pre_callback,
|
||||
std::function<void(const rcl_time_jump_t &)> post_callback,
|
||||
pre_callback_t pre_callback,
|
||||
post_callback_t post_callback,
|
||||
const rcl_jump_threshold_t & threshold);
|
||||
|
||||
std::function<void()> pre_callback;
|
||||
std::function<void(const rcl_time_jump_t &)> post_callback;
|
||||
pre_callback_t pre_callback;
|
||||
post_callback_t post_callback;
|
||||
rcl_jump_threshold_t notice_threshold;
|
||||
};
|
||||
|
||||
@@ -50,38 +51,74 @@ 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();
|
||||
get_clock_handle() noexcept;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rcl_clock_type_t
|
||||
get_clock_type();
|
||||
get_clock_type() const noexcept;
|
||||
|
||||
// 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(
|
||||
std::function<void()> pre_callback,
|
||||
std::function<void(const rcl_time_jump_t &)> post_callback,
|
||||
JumpHandler::pre_callback_t pre_callback,
|
||||
JumpHandler::post_callback_t post_callback,
|
||||
const rcl_jump_threshold_t & threshold);
|
||||
|
||||
private:
|
||||
|
||||
@@ -18,19 +18,30 @@
|
||||
#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, typename PublisherT>
|
||||
template<
|
||||
typename MessageT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename PublisherT = ::rclcpp::Publisher<MessageT, AllocatorT>>
|
||||
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
|
||||
[[deprecated("use alternative rclcpp::create_publisher() signatures")]]
|
||||
std::shared_ptr<PublisherT>
|
||||
create_publisher(
|
||||
rclcpp::node_interfaces::NodeTopicsInterface * node_topics,
|
||||
const std::string & topic_name,
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
const PublisherEventCallbacks & event_callbacks,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group,
|
||||
bool use_intra_process_comms,
|
||||
std::shared_ptr<AllocatorT> allocator)
|
||||
{
|
||||
@@ -39,10 +50,69 @@ create_publisher(
|
||||
|
||||
auto pub = node_topics->create_publisher(
|
||||
topic_name,
|
||||
rclcpp::create_publisher_factory<MessageT, AllocatorT, PublisherT>(allocator),
|
||||
rclcpp::create_publisher_factory<MessageT, AllocatorT, PublisherT>(event_callbacks, allocator),
|
||||
publisher_options,
|
||||
use_intra_process_comms);
|
||||
node_topics->add_publisher(pub);
|
||||
|
||||
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);
|
||||
return std::dynamic_pointer_cast<PublisherT>(pub);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,11 @@
|
||||
#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
|
||||
@@ -32,12 +35,15 @@ 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,
|
||||
@@ -52,7 +58,10 @@ create_subscription(
|
||||
|
||||
auto factory = rclcpp::create_subscription_factory
|
||||
<MessageT, CallbackT, AllocatorT, CallbackMessageT, SubscriptionT>(
|
||||
std::forward<CallbackT>(callback), msg_mem_strat, allocator);
|
||||
std::forward<CallbackT>(callback),
|
||||
event_callbacks,
|
||||
msg_mem_strat,
|
||||
allocator);
|
||||
|
||||
auto sub = node_topics->create_subscription(
|
||||
topic_name,
|
||||
@@ -63,6 +72,75 @@ 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_
|
||||
|
||||
73
rclcpp/include/rclcpp/create_timer.hpp
Normal file
73
rclcpp/include/rclcpp/create_timer.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__CREATE_TIMER_HPP_
|
||||
#define RCLCPP__CREATE_TIMER_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/duration.hpp"
|
||||
# include "rclcpp/node_interfaces/get_node_base_interface.hpp"
|
||||
# include "rclcpp/node_interfaces/get_node_timers_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
/// Create a timer with a given clock
|
||||
/// \internal
|
||||
template<typename CallbackT>
|
||||
typename rclcpp::TimerBase::SharedPtr
|
||||
create_timer(
|
||||
node_interfaces::NodeBaseInterface * node_base,
|
||||
node_interfaces::NodeTimersInterface * node_timers,
|
||||
rclcpp::Clock::SharedPtr clock,
|
||||
rclcpp::Duration period,
|
||||
CallbackT && callback,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr)
|
||||
{
|
||||
auto timer = rclcpp::GenericTimer<CallbackT>::make_shared(
|
||||
clock,
|
||||
period.to_chrono<std::chrono::nanoseconds>(),
|
||||
std::forward<CallbackT>(callback),
|
||||
node_base->get_context());
|
||||
|
||||
node_timers->add_timer(timer, group);
|
||||
return timer;
|
||||
}
|
||||
|
||||
/// Create a timer with a given clock
|
||||
template<typename NodeT, typename CallbackT>
|
||||
typename rclcpp::TimerBase::SharedPtr
|
||||
create_timer(
|
||||
NodeT node,
|
||||
rclcpp::Clock::SharedPtr clock,
|
||||
rclcpp::Duration period,
|
||||
CallbackT && callback,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr)
|
||||
{
|
||||
return create_timer(
|
||||
rclcpp::node_interfaces::get_node_base_interface(node),
|
||||
rclcpp::node_interfaces::get_node_timers_interface(node),
|
||||
clock,
|
||||
period,
|
||||
std::forward<CallbackT>(callback),
|
||||
group);
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__CREATE_TIMER_HPP_
|
||||
@@ -23,91 +23,90 @@
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
class Duration
|
||||
class RCLCPP_PUBLIC Duration
|
||||
{
|
||||
public:
|
||||
RCLCPP_PUBLIC
|
||||
Duration(int32_t seconds, uint32_t nanoseconds);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
explicit Duration(
|
||||
rcl_duration_value_t nanoseconds);
|
||||
explicit Duration(rcl_duration_value_t nanoseconds);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
explicit Duration(
|
||||
std::chrono::nanoseconds nanoseconds);
|
||||
explicit Duration(std::chrono::nanoseconds nanoseconds);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
Duration(
|
||||
const builtin_interfaces::msg::Duration & duration_msg);
|
||||
// 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
|
||||
explicit Duration(const rcl_duration_t & duration);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
Duration(const Duration & rhs);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~Duration();
|
||||
virtual ~Duration() = default;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
operator builtin_interfaces::msg::Duration() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
// cppcheck-suppress operatorEq // this is a false positive from cppcheck
|
||||
Duration &
|
||||
operator=(const Duration & rhs);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
Duration &
|
||||
operator=(const builtin_interfaces::msg::Duration & Duration_msg);
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
static Duration
|
||||
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_;
|
||||
};
|
||||
|
||||
@@ -110,13 +110,15 @@ 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(
|
||||
throw_from_rcl_error [[noreturn]] (
|
||||
rcl_ret_t ret,
|
||||
const std::string & prefix = "",
|
||||
const rcl_error_state_t * error_state = nullptr,
|
||||
void (* reset_error)() = rcl_reset_error);
|
||||
/* *INDENT-ON* */
|
||||
|
||||
class RCLErrorBase
|
||||
{
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -34,6 +35,7 @@
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/utilities.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
#include "rclcpp/scope_exit.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
@@ -242,9 +244,14 @@ public:
|
||||
}
|
||||
std::chrono::nanoseconds timeout_left = timeout_ns;
|
||||
|
||||
while (rclcpp::ok(this->context_)) {
|
||||
if (spinning.exchange(true)) {
|
||||
throw std::runtime_error("spin_until_future_complete() called while already spinning");
|
||||
}
|
||||
RCLCPP_SCOPE_EXIT(this->spinning.store(false); );
|
||||
while (rclcpp::ok(this->context_) && spinning.load()) {
|
||||
// Do one item of work.
|
||||
spin_once(timeout_left);
|
||||
spin_once_impl(timeout_left);
|
||||
|
||||
// Check if the future is set, return SUCCESS if it is.
|
||||
status = future.wait_for(std::chrono::seconds(0));
|
||||
if (status == std::future_status::ready) {
|
||||
@@ -355,6 +362,9 @@ protected:
|
||||
/// Wait set for managing entities that the rmw layer waits on.
|
||||
rcl_wait_set_t wait_set_ = rcl_get_zero_initialized_wait_set();
|
||||
|
||||
// Mutex to protect the subsequent memory_strategy_.
|
||||
std::mutex memory_strategy_mutex_;
|
||||
|
||||
/// The memory strategy: an interface for handling user-defined memory allocation strategies.
|
||||
memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;
|
||||
|
||||
@@ -364,7 +374,12 @@ protected:
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(Executor)
|
||||
|
||||
std::vector<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> weak_nodes_;
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_once_impl(std::chrono::nanoseconds timeout);
|
||||
|
||||
std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> weak_nodes_;
|
||||
std::list<const rcl_guard_condition_t *> guard_conditions_;
|
||||
};
|
||||
|
||||
} // namespace executor
|
||||
|
||||
@@ -48,6 +48,7 @@ public:
|
||||
* \param number_of_threads number of threads to have in the thread pool,
|
||||
* the default 0 will use the number of cpu cores found instead
|
||||
* \param yield_before_execute if true std::this_thread::yield() is called
|
||||
* \param timeout maximum time to wait
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
MultiThreadedExecutor(
|
||||
|
||||
@@ -88,8 +88,24 @@ struct function_traits<std::_Bind<ReturnTypeT(ClassT::*(FArgs ...))(Args ...)>>
|
||||
struct function_traits<std::_Bind<std::_Mem_fn<ReturnTypeT (ClassT::*)(Args ...)>(FArgs ...)>>
|
||||
#elif defined _MSC_VER // MS Visual Studio
|
||||
struct function_traits<
|
||||
std::_Binder<std::_Unforced, ReturnTypeT(__cdecl ClassT::*)(Args ...), FArgs ...>
|
||||
>
|
||||
std::_Binder<std::_Unforced, ReturnTypeT (ClassT::*)(Args ...), FArgs ...>>
|
||||
#else
|
||||
#error "Unsupported C++ compiler / standard library"
|
||||
#endif
|
||||
: function_traits<ReturnTypeT(Args ...)>
|
||||
{};
|
||||
|
||||
// std::bind for object const methods
|
||||
template<typename ClassT, typename ReturnTypeT, typename ... Args, typename ... FArgs>
|
||||
#if defined _LIBCPP_VERSION // libc++ (Clang)
|
||||
struct function_traits<std::__bind<ReturnTypeT (ClassT::*)(Args ...) const, FArgs ...>>
|
||||
#elif defined _GLIBCXX_RELEASE // glibc++ (GNU C++ >= 7.1)
|
||||
struct function_traits<std::_Bind<ReturnTypeT(ClassT::*(FArgs ...))(Args ...) const>>
|
||||
#elif defined __GLIBCXX__ // glibc++ (GNU C++)
|
||||
struct function_traits<std::_Bind<std::_Mem_fn<ReturnTypeT (ClassT::*)(Args ...) const>(FArgs ...)>>
|
||||
#elif defined _MSC_VER // MS Visual Studio
|
||||
struct function_traits<
|
||||
std::_Binder<std::_Unforced, ReturnTypeT (ClassT::*)(Args ...) const, FArgs ...>>
|
||||
#else
|
||||
#error "Unsupported C++ compiler / standard library"
|
||||
#endif
|
||||
@@ -103,7 +119,7 @@ struct function_traits<std::__bind<ReturnTypeT( &)(Args ...), FArgs ...>>
|
||||
#elif defined __GLIBCXX__ // glibc++ (GNU C++)
|
||||
struct function_traits<std::_Bind<ReturnTypeT(*(FArgs ...))(Args ...)>>
|
||||
#elif defined _MSC_VER // MS Visual Studio
|
||||
struct function_traits<std::_Binder<std::_Unforced, ReturnTypeT(__cdecl &)(Args ...), FArgs ...>>
|
||||
struct function_traits<std::_Binder<std::_Unforced, ReturnTypeT( &)(Args ...), FArgs ...>>
|
||||
#else
|
||||
#error "Unsupported C++ compiler / standard library"
|
||||
#endif
|
||||
|
||||
@@ -25,14 +25,15 @@
|
||||
#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.hpp"
|
||||
#include "rclcpp/subscription.hpp"
|
||||
#include "rclcpp/publisher_base.hpp"
|
||||
#include "rclcpp/subscription_base.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
@@ -184,21 +185,11 @@ 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.
|
||||
*/
|
||||
template<typename MessageT, typename Alloc>
|
||||
RCLCPP_PUBLIC
|
||||
uint64_t
|
||||
add_publisher(
|
||||
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;
|
||||
}
|
||||
rclcpp::PublisherBase::SharedPtr publisher,
|
||||
size_t buffer_size = 0);
|
||||
|
||||
/// Unregister a publisher using the publisher's unique id.
|
||||
/**
|
||||
@@ -242,12 +233,11 @@ public:
|
||||
* \return the message sequence number.
|
||||
*/
|
||||
template<
|
||||
typename MessageT, typename Alloc = std::allocator<void>,
|
||||
typename Deleter = std::default_delete<MessageT>>
|
||||
typename MessageT, typename Alloc = std::allocator<void>>
|
||||
uint64_t
|
||||
store_intra_process_message(
|
||||
uint64_t intra_process_publisher_id,
|
||||
std::unique_ptr<MessageT, Deleter> & message)
|
||||
std::shared_ptr<const MessageT> message)
|
||||
{
|
||||
using MRBMessageAlloc = typename std::allocator_traits<Alloc>::template rebind_alloc<MessageT>;
|
||||
using TypedMRB = typename mapped_ring_buffer::MappedRingBuffer<MessageT, MRBMessageAlloc>;
|
||||
@@ -270,6 +260,35 @@ 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
|
||||
@@ -334,10 +353,45 @@ 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_copy_at_key(message_sequence_number, message);
|
||||
typed_buffer->get(message_sequence_number, message);
|
||||
} else {
|
||||
// This is the last one to be returned, transfer ownership.
|
||||
typed_buffer->pop_at_key(message_sequence_number, message);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/mapped_ring_buffer.hpp"
|
||||
#include "rclcpp/publisher.hpp"
|
||||
#include "rclcpp/subscription.hpp"
|
||||
#include "rclcpp/publisher_base.hpp"
|
||||
#include "rclcpp/subscription_base.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -38,7 +39,7 @@ public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(MappedRingBufferBase)
|
||||
};
|
||||
|
||||
/// Ring buffer container of unique_ptr's of T, which can be accessed by a key.
|
||||
/// Ring buffer container of shared_ptr's or unique_ptr's of T, which can be accessed by a key.
|
||||
/**
|
||||
* T must be a CopyConstructable and CopyAssignable.
|
||||
* This class can be used in a container by using the base class MappedRingBufferBase.
|
||||
@@ -64,6 +65,7 @@ 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.
|
||||
@@ -101,57 +103,33 @@ public:
|
||||
* \param value if the key is found, the value is stored in this parameter
|
||||
*/
|
||||
void
|
||||
get_copy_at_key(uint64_t key, ElemUniquePtr & value)
|
||||
get(uint64_t key, ElemUniquePtr & value)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(data_mutex_);
|
||||
auto it = get_iterator_of_key(key);
|
||||
value = nullptr;
|
||||
if (it != elements_.end() && it->in_use) {
|
||||
auto ptr = ElemAllocTraits::allocate(*allocator_.get(), 1);
|
||||
ElemAllocTraits::construct(*allocator_.get(), ptr, *it->value);
|
||||
value = ElemUniquePtr(ptr);
|
||||
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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return ownership of the value stored in the ring buffer, leaving a copy.
|
||||
/**
|
||||
* 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_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) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
/// Return ownership of the value stored in the ring buffer at the given key.
|
||||
/// Share ownership of the value stored in the ring buffer at the given key.
|
||||
/**
|
||||
* The key is matched if an element in the ring buffer has a matching key.
|
||||
*
|
||||
@@ -163,13 +141,90 @@ public:
|
||||
* \param value if the key is found, the value is stored in this parameter
|
||||
*/
|
||||
void
|
||||
pop_at_key(uint64_t key, ElemUniquePtr & value)
|
||||
get(uint64_t key, ConstElemSharedPtr & value)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(data_mutex_);
|
||||
auto it = get_iterator_of_key(key);
|
||||
value.reset();
|
||||
if (it != elements_.end() && it->in_use) {
|
||||
if (!it->shared_value) {
|
||||
// The stored unique_ptr is upgraded to a shared_ptr here.
|
||||
// All the remaining get and pop calls done with unique_ptr
|
||||
// signature will receive a copy.
|
||||
if (!it->unique_value) {
|
||||
throw std::runtime_error("Unexpected empty MappedRingBuffer element.");
|
||||
}
|
||||
it->shared_value = std::move(it->unique_value);
|
||||
}
|
||||
value = it->shared_value;
|
||||
}
|
||||
}
|
||||
|
||||
/// Give the ownership of the stored value to the caller if possible, or copy and release.
|
||||
/**
|
||||
* The key is matched if an element in the ring buffer has a matching key.
|
||||
* This method may allocate in order to return a copy.
|
||||
*
|
||||
* If the stored value is a shared_ptr, it is not possible to downgrade it to a unique_ptr.
|
||||
* In that case, a copy is returned and the stored value is released.
|
||||
*
|
||||
* The key is not guaranteed to be unique, see the class docs for more.
|
||||
*
|
||||
* The contents of value before the method is called are discarded.
|
||||
*
|
||||
* \param key the key associated with the stored value
|
||||
* \param value if the key is found, the value is stored in this parameter
|
||||
*/
|
||||
void
|
||||
pop(uint64_t key, ElemUniquePtr & value)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(data_mutex_);
|
||||
auto it = get_iterator_of_key(key);
|
||||
value = nullptr;
|
||||
if (it != elements_.end() && it->in_use) {
|
||||
value.swap(it->value);
|
||||
if (it->unique_value) {
|
||||
value = std::move(it->unique_value);
|
||||
} else if (it->shared_value) {
|
||||
auto ptr = ElemAllocTraits::allocate(*allocator_.get(), 1);
|
||||
ElemAllocTraits::construct(*allocator_.get(), ptr, *it->shared_value);
|
||||
auto deleter = std::get_deleter<ElemDeleter, const T>(it->shared_value);
|
||||
if (deleter) {
|
||||
value = ElemUniquePtr(ptr, *deleter);
|
||||
} else {
|
||||
value = ElemUniquePtr(ptr);
|
||||
}
|
||||
it->shared_value.reset();
|
||||
} else {
|
||||
throw std::runtime_error("Unexpected empty MappedRingBuffer element.");
|
||||
}
|
||||
it->in_use = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Give the ownership of the stored value to the caller, at the given key.
|
||||
/**
|
||||
* The key is matched if an element in the ring buffer has a matching key.
|
||||
*
|
||||
* The key is not guaranteed to be unique, see the class docs for more.
|
||||
*
|
||||
* The contents of value before the method is called are discarded.
|
||||
*
|
||||
* \param key the key associated with the stored value
|
||||
* \param value if the key is found, the value is stored in this parameter
|
||||
*/
|
||||
void
|
||||
pop(uint64_t key, ConstElemSharedPtr & value)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(data_mutex_);
|
||||
auto it = get_iterator_of_key(key);
|
||||
if (it != elements_.end() && it->in_use) {
|
||||
if (it->shared_value) {
|
||||
value = std::move(it->shared_value);
|
||||
} else if (it->unique_value) {
|
||||
value = std::move(it->unique_value);
|
||||
} else {
|
||||
throw std::runtime_error("Unexpected empty MappedRingBuffer element.");
|
||||
}
|
||||
it->in_use = false;
|
||||
}
|
||||
}
|
||||
@@ -180,29 +235,44 @@ public:
|
||||
* It is up to the user to ensure the key is unique.
|
||||
* This method should not allocate memory.
|
||||
*
|
||||
* After insertion, if a pair was replaced, then value will contain ownership
|
||||
* of that displaced value. Otherwise it will be a nullptr.
|
||||
* After insertion the value will be a nullptr.
|
||||
* If a pair were replaced, its smart pointer is reset.
|
||||
*
|
||||
* \param key the key associated with the value to be stored
|
||||
* \param value the value to store, and optionally the value displaced
|
||||
*/
|
||||
bool
|
||||
push_and_replace(uint64_t key, ElemUniquePtr & value)
|
||||
push_and_replace(uint64_t key, ConstElemSharedPtr value)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(data_mutex_);
|
||||
bool did_replace = elements_[head_].in_use;
|
||||
elements_[head_].key = key;
|
||||
elements_[head_].value.swap(value);
|
||||
elements_[head_].in_use = true;
|
||||
Element & element = elements_[head_];
|
||||
element.key = key;
|
||||
element.unique_value.reset();
|
||||
element.shared_value.reset();
|
||||
element.shared_value = value;
|
||||
element.in_use = true;
|
||||
head_ = (head_ + 1) % elements_.size();
|
||||
return did_replace;
|
||||
}
|
||||
|
||||
/// Insert a key-value pair, displacing an existing pair if necessary.
|
||||
/**
|
||||
* See `bool push_and_replace(uint64_t key, const ConstElemSharedPtr & value)`.
|
||||
*/
|
||||
bool
|
||||
push_and_replace(uint64_t key, ElemUniquePtr && value)
|
||||
push_and_replace(uint64_t key, ElemUniquePtr value)
|
||||
{
|
||||
ElemUniquePtr temp = std::move(value);
|
||||
return push_and_replace(key, temp);
|
||||
std::lock_guard<std::mutex> lock(data_mutex_);
|
||||
bool did_replace = elements_[head_].in_use;
|
||||
Element & element = elements_[head_];
|
||||
element.key = key;
|
||||
element.unique_value.reset();
|
||||
element.shared_value.reset();
|
||||
element.unique_value = std::move(value);
|
||||
element.in_use = true;
|
||||
head_ = (head_ + 1) % elements_.size();
|
||||
return did_replace;
|
||||
}
|
||||
|
||||
/// Return true if the key is found in the ring buffer, otherwise false.
|
||||
@@ -216,27 +286,28 @@ public:
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(MappedRingBuffer<T, Alloc>)
|
||||
|
||||
struct element
|
||||
struct Element
|
||||
{
|
||||
uint64_t key;
|
||||
ElemUniquePtr value;
|
||||
ElemUniquePtr unique_value;
|
||||
ConstElemSharedPtr shared_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_;
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
#ifndef RCLCPP__MEMORY_STRATEGY_HPP_
|
||||
#define RCLCPP__MEMORY_STRATEGY_HPP_
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/allocator.h"
|
||||
#include "rcl/wait.h"
|
||||
@@ -42,15 +42,16 @@ class RCLCPP_PUBLIC MemoryStrategy
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(MemoryStrategy)
|
||||
using WeakNodeVector = std::vector<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>;
|
||||
using WeakNodeList = std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>;
|
||||
|
||||
virtual ~MemoryStrategy() = default;
|
||||
|
||||
virtual bool collect_entities(const WeakNodeVector & weak_nodes) = 0;
|
||||
virtual bool collect_entities(const WeakNodeList & weak_nodes) = 0;
|
||||
|
||||
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;
|
||||
@@ -66,22 +67,22 @@ public:
|
||||
virtual void
|
||||
get_next_subscription(
|
||||
rclcpp::executor::AnyExecutable & any_exec,
|
||||
const WeakNodeVector & weak_nodes) = 0;
|
||||
const WeakNodeList & weak_nodes) = 0;
|
||||
|
||||
virtual void
|
||||
get_next_service(
|
||||
rclcpp::executor::AnyExecutable & any_exec,
|
||||
const WeakNodeVector & weak_nodes) = 0;
|
||||
const WeakNodeList & weak_nodes) = 0;
|
||||
|
||||
virtual void
|
||||
get_next_client(
|
||||
rclcpp::executor::AnyExecutable & any_exec,
|
||||
const WeakNodeVector & weak_nodes) = 0;
|
||||
const WeakNodeList & weak_nodes) = 0;
|
||||
|
||||
virtual void
|
||||
get_next_waitable(
|
||||
rclcpp::executor::AnyExecutable & any_exec,
|
||||
const WeakNodeVector & weak_nodes) = 0;
|
||||
const WeakNodeList & weak_nodes) = 0;
|
||||
|
||||
virtual rcl_allocator_t
|
||||
get_allocator() = 0;
|
||||
@@ -89,42 +90,42 @@ public:
|
||||
static rclcpp::SubscriptionBase::SharedPtr
|
||||
get_subscription_by_handle(
|
||||
std::shared_ptr<const rcl_subscription_t> subscriber_handle,
|
||||
const WeakNodeVector & weak_nodes);
|
||||
const WeakNodeList & weak_nodes);
|
||||
|
||||
static rclcpp::ServiceBase::SharedPtr
|
||||
get_service_by_handle(
|
||||
std::shared_ptr<const rcl_service_t> service_handle,
|
||||
const WeakNodeVector & weak_nodes);
|
||||
const WeakNodeList & weak_nodes);
|
||||
|
||||
static rclcpp::ClientBase::SharedPtr
|
||||
get_client_by_handle(
|
||||
std::shared_ptr<const rcl_client_t> client_handle,
|
||||
const WeakNodeVector & weak_nodes);
|
||||
const WeakNodeList & weak_nodes);
|
||||
|
||||
static rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
|
||||
get_node_by_group(
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group,
|
||||
const WeakNodeVector & weak_nodes);
|
||||
const WeakNodeList & weak_nodes);
|
||||
|
||||
static rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
get_group_by_subscription(
|
||||
rclcpp::SubscriptionBase::SharedPtr subscription,
|
||||
const WeakNodeVector & weak_nodes);
|
||||
const WeakNodeList & weak_nodes);
|
||||
|
||||
static rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
get_group_by_service(
|
||||
rclcpp::ServiceBase::SharedPtr service,
|
||||
const WeakNodeVector & weak_nodes);
|
||||
const WeakNodeList & weak_nodes);
|
||||
|
||||
static rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
get_group_by_client(
|
||||
rclcpp::ClientBase::SharedPtr client,
|
||||
const WeakNodeVector & weak_nodes);
|
||||
const WeakNodeList & weak_nodes);
|
||||
|
||||
static rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
get_group_by_waitable(
|
||||
rclcpp::Waitable::SharedPtr waitable,
|
||||
const WeakNodeVector & weak_nodes);
|
||||
const WeakNodeList & weak_nodes);
|
||||
};
|
||||
|
||||
} // namespace memory_strategy
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
#include "rclcpp/logger.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/message_memory_strategy.hpp"
|
||||
#include "rclcpp/node_options.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_clock_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
|
||||
@@ -53,9 +52,11 @@
|
||||
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_waitables_interface.hpp"
|
||||
#include "rclcpp/node_options.hpp"
|
||||
#include "rclcpp/parameter.hpp"
|
||||
#include "rclcpp/publisher.hpp"
|
||||
#include "rclcpp/publisher_options.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/service.hpp"
|
||||
#include "rclcpp/subscription.hpp"
|
||||
#include "rclcpp/subscription_options.hpp"
|
||||
@@ -144,8 +145,27 @@ public:
|
||||
|
||||
/// Create and return a Publisher.
|
||||
/**
|
||||
* The rclcpp::QoS has several convenient constructors, including a
|
||||
* conversion constructor for size_t, which mimics older API's that
|
||||
* allows just a string and size_t to create a publisher.
|
||||
*
|
||||
* For example, all of these cases will work:
|
||||
*
|
||||
* pub = node->create_publisher<MsgT>("chatter", 10); // implicitly KeepLast
|
||||
* pub = node->create_publisher<MsgT>("chatter", QoS(10)); // implicitly KeepLast
|
||||
* pub = node->create_publisher<MsgT>("chatter", QoS(KeepLast(10)));
|
||||
* pub = node->create_publisher<MsgT>("chatter", QoS(KeepAll()));
|
||||
* pub = node->create_publisher<MsgT>("chatter", QoS(1).best_effort().durability_volatile());
|
||||
* {
|
||||
* rclcpp::QoS custom_qos(KeepLast(10), rmw_qos_profile_sensor_data);
|
||||
* pub = node->create_publisher<MsgT>("chatter", custom_qos);
|
||||
* }
|
||||
*
|
||||
* The publisher options may optionally be passed as the third argument for
|
||||
* any of the above cases.
|
||||
*
|
||||
* \param[in] topic_name The topic for this publisher to publish on.
|
||||
* \param[in] qos_history_depth The depth of the publisher message queue.
|
||||
* \param[in] qos The Quality of Service settings for the publisher.
|
||||
* \param[in] options Additional options for the created Publisher.
|
||||
* \return Shared pointer to the created publisher.
|
||||
*/
|
||||
@@ -156,30 +176,29 @@ public:
|
||||
std::shared_ptr<PublisherT>
|
||||
create_publisher(
|
||||
const std::string & topic_name,
|
||||
size_t qos_history_depth,
|
||||
const PublisherOptionsWithAllocator<AllocatorT> &
|
||||
options = PublisherOptionsWithAllocator<AllocatorT>());
|
||||
const rclcpp::QoS & qos,
|
||||
const PublisherOptionsWithAllocator<AllocatorT> & options =
|
||||
PublisherOptionsWithAllocator<AllocatorT>()
|
||||
);
|
||||
|
||||
/// Create and return a Publisher.
|
||||
/**
|
||||
* \param[in] topic_name The topic for this publisher to publish on.
|
||||
* \param[in] qos_history_depth The depth of the publisher message queue.
|
||||
* \param[in] allocator Optional custom allocator.
|
||||
* \param[in] allocator Custom allocator.
|
||||
* \return Shared pointer to the created publisher.
|
||||
*/
|
||||
template<
|
||||
typename MessageT, typename Alloc = std::allocator<void>,
|
||||
typename PublisherT = ::rclcpp::Publisher<MessageT, Alloc>>
|
||||
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 the create_publisher(const std::string &, size_t, const PublisherOptions<Alloc> & = "
|
||||
"PublisherOptions<Alloc>()) signature instead")]]
|
||||
[[deprecated("use create_publisher(const std::string &, const rclcpp::QoS &, ...) instead")]]
|
||||
std::shared_ptr<PublisherT>
|
||||
create_publisher(
|
||||
const std::string & topic_name,
|
||||
size_t qos_history_depth,
|
||||
std::shared_ptr<Alloc> allocator,
|
||||
IntraProcessSetting use_intra_process_comm = IntraProcessSetting::NodeDefault);
|
||||
std::shared_ptr<AllocatorT> allocator);
|
||||
|
||||
/// Create and return a Publisher.
|
||||
/**
|
||||
@@ -189,14 +208,16 @@ public:
|
||||
* \return Shared pointer to the created publisher.
|
||||
*/
|
||||
template<
|
||||
typename MessageT, typename Alloc = std::allocator<void>,
|
||||
typename PublisherT = ::rclcpp::Publisher<MessageT, Alloc>>
|
||||
typename MessageT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename PublisherT = ::rclcpp::Publisher<MessageT, AllocatorT>>
|
||||
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
|
||||
[[deprecated("use create_publisher(const std::string &, const rclcpp::QoS &, ...) instead")]]
|
||||
std::shared_ptr<PublisherT>
|
||||
create_publisher(
|
||||
const std::string & topic_name,
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_default,
|
||||
std::shared_ptr<Alloc> allocator = nullptr,
|
||||
IntraProcessSetting use_intra_process_comm = IntraProcessSetting::NodeDefault);
|
||||
std::shared_ptr<AllocatorT> allocator = nullptr);
|
||||
|
||||
/// Create and return a Subscription.
|
||||
/**
|
||||
@@ -220,10 +241,10 @@ public:
|
||||
std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos,
|
||||
CallbackT && callback,
|
||||
size_t qos_history_depth,
|
||||
const SubscriptionOptionsWithAllocator<AllocatorT> &
|
||||
options = SubscriptionOptionsWithAllocator<AllocatorT>(),
|
||||
const SubscriptionOptionsWithAllocator<AllocatorT> & options =
|
||||
SubscriptionOptionsWithAllocator<AllocatorT>(),
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, AllocatorT
|
||||
>::SharedPtr
|
||||
@@ -250,6 +271,10 @@ public:
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename SubscriptionT = rclcpp::Subscription<
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, Alloc>>
|
||||
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
|
||||
[[deprecated(
|
||||
"use create_subscription(const std::string &, const rclcpp::QoS &, CallbackT, ...) instead"
|
||||
)]]
|
||||
std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
const std::string & topic_name,
|
||||
@@ -260,8 +285,7 @@ public:
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, Alloc>::SharedPtr
|
||||
msg_mem_strat = nullptr,
|
||||
std::shared_ptr<Alloc> allocator = nullptr,
|
||||
IntraProcessSetting use_intra_process_comm = IntraProcessSetting::NodeDefault);
|
||||
std::shared_ptr<Alloc> allocator = nullptr);
|
||||
|
||||
/// Create and return a Subscription.
|
||||
/**
|
||||
@@ -284,21 +308,21 @@ public:
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename SubscriptionT = rclcpp::Subscription<
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, Alloc>>
|
||||
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
|
||||
[[deprecated(
|
||||
"use the create_subscription(const std::string &, CallbackT &&, size_t, "
|
||||
"const SubscriptionOptions<Alloc> & = SubscriptionOptions<Alloc>(), ...) signature instead")]]
|
||||
"use create_subscription(const std::string &, const rclcpp::QoS &, CallbackT, ...) instead"
|
||||
)]]
|
||||
std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
const std::string & topic_name,
|
||||
CallbackT && callback,
|
||||
size_t qos_history_depth,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr,
|
||||
bool ignore_local_publications = false,
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, Alloc>::SharedPtr
|
||||
msg_mem_strat = nullptr,
|
||||
std::shared_ptr<Alloc> allocator = nullptr,
|
||||
IntraProcessSetting use_intra_process_comm = IntraProcessSetting::NodeDefault);
|
||||
std::shared_ptr<Alloc> allocator = nullptr);
|
||||
|
||||
/// Create a timer.
|
||||
/**
|
||||
@@ -313,7 +337,13 @@ public:
|
||||
CallbackT callback,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
/* Create and return a Client. */
|
||||
/// Create and return a Client.
|
||||
/**
|
||||
* \param[in] service_name The topic to service on.
|
||||
* \param[in] qos_profile rmw_qos_profile_t Quality of service profile for client.
|
||||
* \param[in] group Callback group to call the service.
|
||||
* \return Shared pointer to the created client.
|
||||
*/
|
||||
template<typename ServiceT>
|
||||
typename rclcpp::Client<ServiceT>::SharedPtr
|
||||
create_client(
|
||||
@@ -321,7 +351,14 @@ public:
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
/* Create and return a Service. */
|
||||
/// Create and return a Service.
|
||||
/**
|
||||
* \param[in] service_name The topic to service on.
|
||||
* \param[in] callback User-defined callback function.
|
||||
* \param[in] qos_profile rmw_qos_profile_t Quality of service profile for client.
|
||||
* \param[in] group Callback group to call the service.
|
||||
* \return Shared pointer to the created service.
|
||||
*/
|
||||
template<typename ServiceT, typename CallbackT>
|
||||
typename rclcpp::Service<ServiceT>::SharedPtr
|
||||
create_service(
|
||||
@@ -492,6 +529,7 @@ public:
|
||||
* rclcpp::NodeOptions::allow_undeclared_parameters set to true.
|
||||
* If undeclared parameters are allowed, then the parameter is implicitly
|
||||
* declared with the default parameter meta data before being set.
|
||||
* Parameter overrides are ignored by set_parameter.
|
||||
*
|
||||
* This method will result in any callback registered with
|
||||
* set_on_parameters_set_callback to be called.
|
||||
@@ -916,6 +954,11 @@ public:
|
||||
void
|
||||
register_param_change_callback(CallbackT && callback);
|
||||
|
||||
/// Get the fully-qualified names of all available nodes.
|
||||
/**
|
||||
* The fully-qualified name includes the local namespace and name of the node.
|
||||
* \return A vector of fully-qualified names of nodes.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<std::string>
|
||||
get_node_names() const;
|
||||
@@ -1112,14 +1155,27 @@ public:
|
||||
* with a leading '/'.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
Node::SharedPtr
|
||||
rclcpp::Node::SharedPtr
|
||||
create_sub_node(const std::string & sub_namespace);
|
||||
|
||||
/// Return the NodeOptions used when creating this node.
|
||||
RCLCPP_PUBLIC
|
||||
const NodeOptions &
|
||||
const rclcpp::NodeOptions &
|
||||
get_node_options() const;
|
||||
|
||||
/// Manually assert that this Node is alive (for RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_NODE).
|
||||
/**
|
||||
* If the rmw Liveliness policy is set to RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_NODE, the creator
|
||||
* of this node 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;
|
||||
|
||||
protected:
|
||||
/// Construct a sub-node, which will extend the namespace of all entities created with it.
|
||||
/**
|
||||
@@ -1151,7 +1207,7 @@ private:
|
||||
rclcpp::node_interfaces::NodeTimeSourceInterface::SharedPtr node_time_source_;
|
||||
rclcpp::node_interfaces::NodeWaitablesInterface::SharedPtr node_waitables_;
|
||||
|
||||
const NodeOptions node_options_;
|
||||
const rclcpp::NodeOptions node_options_;
|
||||
const std::string sub_namespace_;
|
||||
const std::string effective_namespace_;
|
||||
};
|
||||
|
||||
@@ -36,11 +36,12 @@
|
||||
#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"
|
||||
|
||||
@@ -67,66 +68,42 @@ template<typename MessageT, typename AllocatorT, typename PublisherT>
|
||||
std::shared_ptr<PublisherT>
|
||||
Node::create_publisher(
|
||||
const std::string & topic_name,
|
||||
size_t qos_history_depth,
|
||||
const rclcpp::QoS & qos,
|
||||
const PublisherOptionsWithAllocator<AllocatorT> & options)
|
||||
{
|
||||
std::shared_ptr<AllocatorT> allocator = options.allocator;
|
||||
if (!allocator) {
|
||||
allocator = std::make_shared<AllocatorT>();
|
||||
}
|
||||
rmw_qos_profile_t qos_profile = options.qos_profile;
|
||||
qos_profile.depth = qos_history_depth;
|
||||
|
||||
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 = this->get_node_options().use_intra_process_comms();
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unrecognized IntraProcessSetting value");
|
||||
break;
|
||||
}
|
||||
|
||||
return rclcpp::create_publisher<MessageT, AllocatorT, PublisherT>(
|
||||
this->node_topics_.get(),
|
||||
*this,
|
||||
extend_name_with_sub_namespace(topic_name, this->get_sub_namespace()),
|
||||
qos_profile,
|
||||
use_intra_process,
|
||||
allocator);
|
||||
qos,
|
||||
options);
|
||||
}
|
||||
|
||||
template<typename MessageT, typename Alloc, typename PublisherT>
|
||||
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<Alloc> allocator,
|
||||
IntraProcessSetting use_intra_process_comm)
|
||||
const std::string & topic_name,
|
||||
size_t qos_history_depth,
|
||||
std::shared_ptr<AllocatorT> allocator)
|
||||
{
|
||||
PublisherOptionsWithAllocator<Alloc> pub_options;
|
||||
PublisherOptionsWithAllocator<AllocatorT> pub_options;
|
||||
pub_options.allocator = allocator;
|
||||
pub_options.use_intra_process_comm = use_intra_process_comm;
|
||||
return this->create_publisher<MessageT, Alloc, PublisherT>(
|
||||
topic_name, qos_history_depth, pub_options);
|
||||
return this->create_publisher<MessageT, AllocatorT, PublisherT>(
|
||||
topic_name, rclcpp::QoS(rclcpp::KeepLast(qos_history_depth)), pub_options);
|
||||
}
|
||||
|
||||
template<typename MessageT, typename Alloc, typename PublisherT>
|
||||
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<Alloc> allocator, IntraProcessSetting use_intra_process_comm)
|
||||
const std::string & topic_name,
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
std::shared_ptr<AllocatorT> allocator)
|
||||
{
|
||||
PublisherOptionsWithAllocator<Alloc> pub_options;
|
||||
pub_options.qos_profile = qos_profile;
|
||||
rclcpp::QoS qos(rclcpp::QoSInitialization::from_rmw(qos_profile));
|
||||
qos.get_rmw_qos_profile() = qos_profile;
|
||||
|
||||
PublisherOptionsWithAllocator<AllocatorT> pub_options;
|
||||
pub_options.allocator = allocator;
|
||||
pub_options.use_intra_process_comm = use_intra_process_comm;
|
||||
return this->create_publisher<MessageT, Alloc, PublisherT>(
|
||||
topic_name, qos_profile.depth, pub_options);
|
||||
return this->create_publisher<MessageT, AllocatorT, PublisherT>(topic_name, qos, pub_options);
|
||||
}
|
||||
|
||||
template<
|
||||
@@ -137,55 +114,20 @@ template<
|
||||
std::shared_ptr<SubscriptionT>
|
||||
Node::create_subscription(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos,
|
||||
CallbackT && callback,
|
||||
size_t qos_history_depth,
|
||||
const SubscriptionOptionsWithAllocator<AllocatorT> & options,
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, AllocatorT>::SharedPtr
|
||||
msg_mem_strat)
|
||||
{
|
||||
using CallbackMessageT = typename rclcpp::subscription_traits::has_message_type<CallbackT>::type;
|
||||
|
||||
std::shared_ptr<AllocatorT> allocator = options.allocator;
|
||||
if (!allocator) {
|
||||
allocator = std::make_shared<AllocatorT>();
|
||||
}
|
||||
|
||||
rmw_qos_profile_t qos_profile = options.qos_profile;
|
||||
qos_profile.depth = qos_history_depth;
|
||||
|
||||
if (!msg_mem_strat) {
|
||||
using rclcpp::message_memory_strategy::MessageMemoryStrategy;
|
||||
msg_mem_strat = MessageMemoryStrategy<CallbackMessageT, AllocatorT>::create_default();
|
||||
}
|
||||
|
||||
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 = this->get_node_options().use_intra_process_comms();
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unrecognized IntraProcessSetting value");
|
||||
break;
|
||||
}
|
||||
|
||||
return rclcpp::create_subscription<
|
||||
MessageT, CallbackT, AllocatorT, CallbackMessageT, SubscriptionT>(
|
||||
this->node_topics_.get(),
|
||||
return rclcpp::create_subscription<MessageT>(
|
||||
*this,
|
||||
extend_name_with_sub_namespace(topic_name, this->get_sub_namespace()),
|
||||
qos,
|
||||
std::forward<CallbackT>(callback),
|
||||
qos_profile,
|
||||
options.callback_group,
|
||||
options.ignore_local_publications,
|
||||
use_intra_process,
|
||||
msg_mem_strat,
|
||||
allocator);
|
||||
options,
|
||||
msg_mem_strat);
|
||||
}
|
||||
|
||||
template<
|
||||
@@ -203,18 +145,18 @@ Node::create_subscription(
|
||||
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,
|
||||
IntraProcessSetting use_intra_process_comm)
|
||||
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.qos_profile = qos_profile;
|
||||
sub_options.callback_group = group;
|
||||
sub_options.ignore_local_publications = ignore_local_publications;
|
||||
sub_options.allocator = allocator;
|
||||
sub_options.use_intra_process_comm = use_intra_process_comm;
|
||||
|
||||
return this->create_subscription<MessageT, CallbackT, Alloc, SubscriptionT>(
|
||||
topic_name, std::forward<CallbackT>(callback), qos_profile.depth, sub_options, msg_mem_strat);
|
||||
topic_name, qos, std::forward<CallbackT>(callback), sub_options, msg_mem_strat);
|
||||
}
|
||||
|
||||
template<
|
||||
@@ -232,17 +174,19 @@ Node::create_subscription(
|
||||
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,
|
||||
IntraProcessSetting use_intra_process_comm)
|
||||
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;
|
||||
sub_options.use_intra_process_comm = use_intra_process_comm;
|
||||
|
||||
return this->create_subscription<MessageT, CallbackT, Alloc, SubscriptionT>(
|
||||
topic_name, std::forward<CallbackT>(callback), qos_history_depth, sub_options, msg_mem_strat);
|
||||
topic_name,
|
||||
rclcpp::QoS(rclcpp::KeepLast(qos_history_depth)),
|
||||
std::forward<CallbackT>(callback),
|
||||
sub_options,
|
||||
msg_mem_strat);
|
||||
}
|
||||
|
||||
template<typename DurationRepT, typename DurationT, typename CallbackT>
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__GET_NODE_BASE_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__GET_NODE_BASE_INTERFACE_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
|
||||
/// This header provides the get_node_base_interface() template function.
|
||||
/**
|
||||
* This function is useful for getting the NodeBaseInterface pointer from
|
||||
* various kinds of Node-like classes.
|
||||
*
|
||||
* It's able to get the NodeBaseInterface pointer so long as the class
|
||||
* has a method called ``get_node_base_interface()`` which returns
|
||||
* either a pointer (const or not) to a NodeBaseInterface or a
|
||||
* std::shared_ptr to a NodeBaseInterface.
|
||||
*/
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// This is a meta-programming checker for if a given Node-like object has a
|
||||
// getter called get_node_base_interface() which returns various types,
|
||||
// e.g. const pointer or a shared pointer.
|
||||
template<typename NodeType, typename ReturnType>
|
||||
struct has_get_node_base_interface
|
||||
{
|
||||
private:
|
||||
template<typename T>
|
||||
static constexpr
|
||||
auto
|
||||
check(T *)->typename std::is_same<
|
||||
decltype(std::declval<T>().get_node_base_interface()),
|
||||
ReturnType
|
||||
>::type;
|
||||
|
||||
template<typename>
|
||||
static constexpr
|
||||
std::false_type
|
||||
check(...);
|
||||
|
||||
public:
|
||||
using type = decltype(check<NodeType>(nullptr));
|
||||
static constexpr bool value = type::value;
|
||||
};
|
||||
|
||||
// If NodeType is a pointer to NodeBaseInterface already (just normal function overload).
|
||||
inline
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface_from_pointer(rclcpp::node_interfaces::NodeBaseInterface * pointer)
|
||||
{
|
||||
return pointer;
|
||||
}
|
||||
|
||||
// If NodeType has a method called get_node_base_interface() which returns a shared pointer.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<has_get_node_base_interface<
|
||||
typename std::remove_pointer<NodeType>::type,
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface>
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface_from_pointer(NodeType node_pointer)
|
||||
{
|
||||
return node_pointer->get_node_base_interface().get();
|
||||
}
|
||||
|
||||
// If NodeType has a method called get_node_base_interface() which returns a pointer.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<has_get_node_base_interface<
|
||||
typename std::remove_pointer<NodeType>::type,
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface_from_pointer(NodeType node_pointer)
|
||||
{
|
||||
return node_pointer->get_node_base_interface();
|
||||
}
|
||||
|
||||
// Forward shared_ptr's to const node pointer signatures.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<std::is_same<
|
||||
NodeType,
|
||||
typename std::shared_ptr<typename std::remove_pointer<NodeType>::type::element_type> *
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface_from_pointer(NodeType node_shared_pointer)
|
||||
{
|
||||
return get_node_base_interface_from_pointer(node_shared_pointer->get());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Get the NodeBaseInterface as a pointer from a pointer to a "Node like" object.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface(NodeType node_pointer)
|
||||
{
|
||||
// Forward pointers to detail implmentation directly.
|
||||
return detail::get_node_base_interface_from_pointer(node_pointer);
|
||||
}
|
||||
|
||||
/// Get the NodeBaseInterface as a pointer from a "Node like" object.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<
|
||||
!std::is_pointer<typename std::remove_reference<NodeType>::type>::value, int
|
||||
>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface(NodeType && node_reference)
|
||||
{
|
||||
// Forward references to detail implmentation as a pointer.
|
||||
return detail::get_node_base_interface_from_pointer(&node_reference);
|
||||
}
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__GET_NODE_BASE_INTERFACE_HPP_
|
||||
@@ -0,0 +1,149 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__GET_NODE_TIMERS_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__GET_NODE_TIMERS_INTERFACE_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
|
||||
|
||||
/// This header provides the get_node_timers_interface() template function.
|
||||
/**
|
||||
* This function is useful for getting the NodeTimersInterface pointer from
|
||||
* various kinds of Node-like classes.
|
||||
*
|
||||
* It's able to get the NodeTimersInterface pointer so long as the class
|
||||
* has a method called ``get_node_timers_interface()`` which returns
|
||||
* either a pointer (const or not) to a NodeTimersInterface or a
|
||||
* std::shared_ptr to a NodeTimersInterface.
|
||||
*/
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// This is a meta-programming checker for if a given Node-like object has a
|
||||
// getter called get_node_timers_interface() which returns various types,
|
||||
// e.g. const pointer or a shared pointer.
|
||||
template<typename NodeType, typename ReturnType>
|
||||
struct has_get_node_timers_interface
|
||||
{
|
||||
private:
|
||||
template<typename T>
|
||||
static constexpr
|
||||
auto
|
||||
check(T *)->typename std::is_same<
|
||||
decltype(std::declval<T>().get_node_timers_interface()),
|
||||
ReturnType
|
||||
>::type;
|
||||
|
||||
template<typename>
|
||||
static constexpr
|
||||
std::false_type
|
||||
check(...);
|
||||
|
||||
public:
|
||||
using type = decltype(check<NodeType>(nullptr));
|
||||
static constexpr bool value = type::value;
|
||||
};
|
||||
|
||||
// If NodeType is a pointer to NodeTimersInterface already (just normal function overload).
|
||||
inline
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface_from_pointer(rclcpp::node_interfaces::NodeTimersInterface * pointer)
|
||||
{
|
||||
return pointer;
|
||||
}
|
||||
|
||||
// If NodeType has a method called get_node_timers_interface() which returns a shared pointer.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<has_get_node_timers_interface<
|
||||
typename std::remove_pointer<NodeType>::type,
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeTimersInterface>
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface_from_pointer(NodeType node_pointer)
|
||||
{
|
||||
return node_pointer->get_node_timers_interface().get();
|
||||
}
|
||||
|
||||
// If NodeType has a method called get_node_timers_interface() which returns a pointer.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<has_get_node_timers_interface<
|
||||
typename std::remove_pointer<NodeType>::type,
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface_from_pointer(NodeType node_pointer)
|
||||
{
|
||||
return node_pointer->get_node_timers_interface();
|
||||
}
|
||||
|
||||
// Forward shared_ptr's to const node pointer signatures.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<std::is_same<
|
||||
NodeType,
|
||||
typename std::shared_ptr<typename std::remove_pointer<NodeType>::type::element_type> *
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface_from_pointer(NodeType node_shared_pointer)
|
||||
{
|
||||
return get_node_timers_interface_from_pointer(node_shared_pointer->get());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Get the NodeTimersInterface as a pointer from a pointer to a "Node like" object.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface(NodeType node_pointer)
|
||||
{
|
||||
// Forward pointers to detail implmentation directly.
|
||||
return detail::get_node_timers_interface_from_pointer(node_pointer);
|
||||
}
|
||||
|
||||
/// Get the NodeTimersInterface as a pointer from a "Node like" object.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<
|
||||
!std::is_pointer<typename std::remove_reference<NodeType>::type>::value, int
|
||||
>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface(NodeType && node_reference)
|
||||
{
|
||||
// Forward references to detail implmentation as a pointer.
|
||||
return detail::get_node_timers_interface_from_pointer(&node_reference);
|
||||
}
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__GET_NODE_TIMERS_INTERFACE_HPP_
|
||||
@@ -0,0 +1,149 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__GET_NODE_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(node_pointer);
|
||||
}
|
||||
|
||||
/// Get the NodeTopicsInterface as a pointer from a "Node like" object.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<
|
||||
!std::is_pointer<typename std::remove_reference<NodeType>::type>::value, int
|
||||
>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::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_
|
||||
@@ -19,10 +19,11 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/node.h"
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_options.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_options.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
@@ -34,13 +35,15 @@ namespace node_interfaces
|
||||
class NodeBase : public NodeBaseInterface
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeBaseInterface)
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeBase)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
NodeBase(
|
||||
const std::string & node_name,
|
||||
const std::string & namespace_,
|
||||
const NodeOptions & options);
|
||||
rclcpp::Context::SharedPtr context,
|
||||
const rcl_node_options_t & rcl_node_options,
|
||||
bool use_intra_process_default);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
@@ -86,6 +89,11 @@ 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
|
||||
@@ -121,10 +129,16 @@ 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_;
|
||||
|
||||
|
||||
@@ -102,6 +102,12 @@ 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
|
||||
@@ -149,6 +155,12 @@ 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
|
||||
|
||||
@@ -63,13 +63,13 @@ public:
|
||||
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,
|
||||
const std::vector<Parameter> & parameter_overrides,
|
||||
bool start_parameter_services,
|
||||
bool start_parameter_event_publisher,
|
||||
const rmw_qos_profile_t & parameter_event_qos_profile,
|
||||
const rclcpp::QoS & parameter_event_qos,
|
||||
const rclcpp::PublisherOptionsBase & parameter_event_publisher_options,
|
||||
bool allow_undeclared_parameters,
|
||||
bool automatically_declare_initial_parameters);
|
||||
bool automatically_declare_parameters_from_overrides);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
@@ -143,7 +143,7 @@ public:
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::map<std::string, rclcpp::ParameterValue> &
|
||||
get_initial_parameter_values() const override;
|
||||
get_parameter_overrides() const override;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(NodeParameters)
|
||||
@@ -154,7 +154,7 @@ private:
|
||||
|
||||
std::map<std::string, ParameterInfo> parameters_;
|
||||
|
||||
std::map<std::string, rclcpp::ParameterValue> initial_parameter_values_;
|
||||
std::map<std::string, rclcpp::ParameterValue> parameter_overrides_;
|
||||
|
||||
bool allow_undeclared_ = false;
|
||||
|
||||
|
||||
@@ -51,8 +51,9 @@ public:
|
||||
const rclcpp::ParameterValue &
|
||||
declare_parameter(
|
||||
const std::string & name,
|
||||
const rclcpp::ParameterValue & default_value,
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor) = 0;
|
||||
const rclcpp::ParameterValue & default_value = rclcpp::ParameterValue(),
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
|
||||
rcl_interfaces::msg::ParameterDescriptor()) = 0;
|
||||
|
||||
/// Undeclare a parameter.
|
||||
/**
|
||||
@@ -183,7 +184,7 @@ public:
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
const std::map<std::string, rclcpp::ParameterValue> &
|
||||
get_initial_parameter_values() const = 0;
|
||||
get_parameter_overrides() const = 0;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
|
||||
@@ -42,44 +42,44 @@ public:
|
||||
explicit NodeTopics(rclcpp::node_interfaces::NodeBaseInterface * node_base);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
~NodeTopics();
|
||||
~NodeTopics() override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::PublisherBase::SharedPtr
|
||||
create_publisher(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::PublisherFactory & publisher_factory,
|
||||
rcl_publisher_options_t & publisher_options,
|
||||
bool use_intra_process);
|
||||
const rcl_publisher_options_t & publisher_options,
|
||||
bool use_intra_process) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
add_publisher(
|
||||
rclcpp::PublisherBase::SharedPtr publisher);
|
||||
rclcpp::PublisherBase::SharedPtr publisher,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::SubscriptionBase::SharedPtr
|
||||
create_subscription(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::SubscriptionFactory & subscription_factory,
|
||||
rcl_subscription_options_t & subscription_options,
|
||||
bool use_intra_process);
|
||||
const rcl_subscription_options_t & subscription_options,
|
||||
bool use_intra_process) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
add_subscription(
|
||||
rclcpp::SubscriptionBase::SharedPtr subscription,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group);
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface() const override;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(NodeTopics)
|
||||
|
||||
NodeBaseInterface * node_base_;
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base_;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
|
||||
@@ -50,14 +50,15 @@ public:
|
||||
create_publisher(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::PublisherFactory & publisher_factory,
|
||||
rcl_publisher_options_t & publisher_options,
|
||||
const rcl_publisher_options_t & publisher_options,
|
||||
bool use_intra_process) = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
add_publisher(
|
||||
rclcpp::PublisherBase::SharedPtr publisher) = 0;
|
||||
rclcpp::PublisherBase::SharedPtr publisher,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group) = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
@@ -65,7 +66,7 @@ public:
|
||||
create_subscription(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::SubscriptionFactory & subscription_factory,
|
||||
rcl_subscription_options_t & subscription_options,
|
||||
const rcl_subscription_options_t & subscription_options,
|
||||
bool use_intra_process) = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
@@ -74,6 +75,11 @@ 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
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#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
|
||||
@@ -38,14 +40,16 @@ public:
|
||||
*
|
||||
* - context = rclcpp::contexts::default_context::get_global_default_context()
|
||||
* - arguments = {}
|
||||
* - initial_parameters = {}
|
||||
* - parameter_overrides = {}
|
||||
* - use_global_arguments = true
|
||||
* - use_intra_process_comms = false
|
||||
* - start_parameter_services = true
|
||||
* - start_parameter_event_publisher = true
|
||||
* - parameter_event_qos_profile = rmw_qos_profile_parameter_events
|
||||
* - 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
|
||||
* - automatically_declare_parameters_from_overrides = false
|
||||
* - allocator = rcl_get_default_allocator()
|
||||
*
|
||||
* \param[in] allocator allocator to use in construction of NodeOptions.
|
||||
@@ -103,31 +107,31 @@ public:
|
||||
NodeOptions &
|
||||
arguments(const std::vector<std::string> & arguments);
|
||||
|
||||
/// Return a reference to the list of initial parameters.
|
||||
/// Return a reference to the list of parameter overrides.
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rclcpp::Parameter> &
|
||||
initial_parameters();
|
||||
parameter_overrides();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::vector<rclcpp::Parameter> &
|
||||
initial_parameters() const;
|
||||
parameter_overrides() const;
|
||||
|
||||
/// Set the initial parameters, return this for parameter idiom.
|
||||
/// Set the parameters overrides, return this for parameter idiom.
|
||||
/**
|
||||
* These initial parameter values are used to change the initial value
|
||||
* These parameter overrides 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);
|
||||
parameter_overrides(const std::vector<rclcpp::Parameter> & parameter_overrides);
|
||||
|
||||
/// Append a single initial parameter, parameter idiom style.
|
||||
/// Append a single parameter override, parameter idiom style.
|
||||
template<typename ParameterT>
|
||||
NodeOptions &
|
||||
append_initial_parameter(const std::string & name, const ParameterT & value)
|
||||
append_parameter_override(const std::string & name, const ParameterT & value)
|
||||
{
|
||||
this->initial_parameters().emplace_back(name, rclcpp::ParameterValue(value));
|
||||
this->parameter_overrides().emplace_back(name, rclcpp::ParameterValue(value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -202,18 +206,36 @@ public:
|
||||
NodeOptions &
|
||||
start_parameter_event_publisher(bool start_parameter_event_publisher);
|
||||
|
||||
/// Return a reference to the parameter_event_qos_profile QoS.
|
||||
/// Return a reference to the parameter_event_qos QoS.
|
||||
RCLCPP_PUBLIC
|
||||
const rmw_qos_profile_t &
|
||||
parameter_event_qos_profile() const;
|
||||
const rclcpp::QoS &
|
||||
parameter_event_qos() const;
|
||||
|
||||
/// Set the parameter_event_qos_profile QoS, return this for parameter idiom.
|
||||
/// 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_profile(const rmw_qos_profile_t & parameter_event_qos_profile);
|
||||
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
|
||||
@@ -225,29 +247,35 @@ public:
|
||||
* 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.
|
||||
*
|
||||
* This option being true does not affect parameter_overrides, as the first
|
||||
* set action will implicitly declare the parameter and therefore consider
|
||||
* any parameter overrides.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
NodeOptions &
|
||||
allow_undeclared_parameters(bool allow_undeclared_parameters);
|
||||
|
||||
/// Return the automatically_declare_initial_parameters flag.
|
||||
/// Return the automatically_declare_parameters_from_overrides flag.
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
automatically_declare_initial_parameters() const;
|
||||
automatically_declare_parameters_from_overrides() const;
|
||||
|
||||
/// Set the automatically_declare_initial_parameters, return this.
|
||||
/// Set the automatically_declare_parameters_from_overrides, return this.
|
||||
/**
|
||||
* If true, automatically iterate through the node's initial parameters and
|
||||
* If true, automatically iterate through the node's parameter overrides 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.
|
||||
* Otherwise, parameters passed to the node's parameter_overrides, and/or the
|
||||
* global arguments (e.g. parameter overrides from a YAML file), which are
|
||||
* not explicitly declared will not appear on the node at all, even if
|
||||
* `allow_undeclared_parameters` is true.
|
||||
* 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);
|
||||
automatically_declare_parameters_from_overrides(
|
||||
bool automatically_declare_parameters_from_overrides);
|
||||
|
||||
/// Return the rcl_allocator_t to be used.
|
||||
RCLCPP_PUBLIC
|
||||
@@ -280,7 +308,7 @@ private:
|
||||
|
||||
std::vector<std::string> arguments_ {};
|
||||
|
||||
std::vector<rclcpp::Parameter> initial_parameters_ {};
|
||||
std::vector<rclcpp::Parameter> parameter_overrides_ {};
|
||||
|
||||
bool use_global_arguments_ {true};
|
||||
|
||||
@@ -290,11 +318,15 @@ private:
|
||||
|
||||
bool start_parameter_event_publisher_ {true};
|
||||
|
||||
rmw_qos_profile_t parameter_event_qos_profile_ {rmw_qos_profile_parameter_events};
|
||||
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};
|
||||
bool automatically_declare_parameters_from_overrides_ {false};
|
||||
|
||||
rcl_allocator_t allocator_ {rcl_get_default_allocator()};
|
||||
};
|
||||
|
||||
@@ -46,6 +46,15 @@ class AsyncParametersClient
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(AsyncParametersClient)
|
||||
|
||||
/// Create an async parameters client.
|
||||
/**
|
||||
* \param[in] node_base_interface The node base interface of the corresponding node.
|
||||
* \param[in] node_topics_interface Node topic base interface.
|
||||
* \param[in] node_graph_interface The node graph interface of the corresponding node.
|
||||
* \param[in] node_services_interface Node service interface.
|
||||
* \param[in] remote_node_name (optional) name of the remote node
|
||||
* \param[in] qos_profile (optional) The rmw qos profile to use to subscribe
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
AsyncParametersClient(
|
||||
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface,
|
||||
@@ -55,12 +64,24 @@ public:
|
||||
const std::string & remote_node_name = "",
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters);
|
||||
|
||||
/// Constructor
|
||||
/**
|
||||
* \param[in] node The async paramters client will be added to this node.
|
||||
* \param[in] remote_node_name (optional) name of the remote node
|
||||
* \param[in] qos_profile (optional) The rmw qos profile to use to subscribe
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
AsyncParametersClient(
|
||||
const rclcpp::Node::SharedPtr node,
|
||||
const std::string & remote_node_name = "",
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters);
|
||||
|
||||
/// Constructor
|
||||
/**
|
||||
* \param[in] node The async paramters client will be added to this node.
|
||||
* \param[in] remote_node_name (optional) name of the remote node
|
||||
* \param[in] qos_profile (optional) The rmw qos profile to use to subscribe
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
AsyncParametersClient(
|
||||
rclcpp::Node * node,
|
||||
@@ -110,28 +131,50 @@ public:
|
||||
|
||||
template<
|
||||
typename CallbackT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename SubscriptionT =
|
||||
rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent, Alloc>>
|
||||
typename AllocatorT = std::allocator<void>>
|
||||
typename rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr
|
||||
on_parameter_event(CallbackT && callback)
|
||||
on_parameter_event(
|
||||
CallbackT && callback,
|
||||
const rclcpp::QoS & qos = (
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events))
|
||||
),
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
|
||||
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
|
||||
))
|
||||
{
|
||||
using rclcpp::message_memory_strategy::MessageMemoryStrategy;
|
||||
auto msg_mem_strat =
|
||||
MessageMemoryStrategy<rcl_interfaces::msg::ParameterEvent, Alloc>::create_default();
|
||||
return this->on_parameter_event(
|
||||
this->node_topics_interface_,
|
||||
callback,
|
||||
qos,
|
||||
options);
|
||||
}
|
||||
|
||||
using rcl_interfaces::msg::ParameterEvent;
|
||||
return rclcpp::create_subscription<
|
||||
ParameterEvent, CallbackT, Alloc, ParameterEvent, SubscriptionT>(
|
||||
this->node_topics_interface_.get(),
|
||||
/**
|
||||
* 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 CallbackT,
|
||||
typename NodeT,
|
||||
typename AllocatorT = std::allocator<void>>
|
||||
static typename rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr
|
||||
on_parameter_event(
|
||||
NodeT && node,
|
||||
CallbackT && callback,
|
||||
const rclcpp::QoS & qos = (
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events))
|
||||
),
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
|
||||
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
|
||||
))
|
||||
{
|
||||
return rclcpp::create_subscription<rcl_interfaces::msg::ParameterEvent>(
|
||||
node,
|
||||
"parameter_events",
|
||||
qos,
|
||||
std::forward<CallbackT>(callback),
|
||||
rmw_qos_profile_default,
|
||||
nullptr, // group,
|
||||
false, // ignore_local_publications,
|
||||
false, // use_intra_process_comms_,
|
||||
msg_mem_strat,
|
||||
std::make_shared<Alloc>());
|
||||
options);
|
||||
}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
@@ -154,7 +197,7 @@ protected:
|
||||
wait_for_service_nanoseconds(std::chrono::nanoseconds timeout);
|
||||
|
||||
private:
|
||||
const rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_interface_;
|
||||
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_;
|
||||
@@ -271,7 +314,26 @@ public:
|
||||
typename rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr
|
||||
on_parameter_event(CallbackT && callback)
|
||||
{
|
||||
return async_parameters_client_->on_parameter_event(std::forward<CallbackT>(callback));
|
||||
return async_parameters_client_->on_parameter_event(
|
||||
std::forward<CallbackT>(callback));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 CallbackT,
|
||||
typename NodeT>
|
||||
static typename rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr
|
||||
on_parameter_event(
|
||||
NodeT && node,
|
||||
CallbackT && callback)
|
||||
{
|
||||
return AsyncParametersClient::on_parameter_event(
|
||||
node,
|
||||
std::forward<CallbackT>(callback));
|
||||
}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/publisher.h"
|
||||
@@ -31,167 +32,15 @@
|
||||
|
||||
#include "rclcpp/allocator/allocator_common.hpp"
|
||||
#include "rclcpp/allocator/allocator_deleter.hpp"
|
||||
#include "rclcpp/intra_process_manager.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/publisher_base.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
// Forward declaration is used for friend statement.
|
||||
namespace node_interfaces
|
||||
{
|
||||
class NodeTopicsInterface;
|
||||
}
|
||||
|
||||
namespace intra_process_manager
|
||||
{
|
||||
/**
|
||||
* NOTE(ivanpauno): IntraProcessManager is forward declared here, avoiding a circular inclusion between intra_process_manager.hpp and publisher.hpp.
|
||||
* SharedPtr and WeakPtr of the IntraProcessManager are defined again here, to avoid a warning for accessing a member of a forward declared class.
|
||||
*/
|
||||
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 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;
|
||||
|
||||
/// 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 StoreMessageCallbackT = std::function<uint64_t(uint64_t, void *, const std::type_info &)>;
|
||||
using IntraProcessManagerSharedPtr =
|
||||
std::shared_ptr<rclcpp::intra_process_manager::IntraProcessManager>;
|
||||
|
||||
/// Implementation utility function used to setup intra process publishing after creation.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
setup_intra_process(
|
||||
uint64_t intra_process_publisher_id,
|
||||
StoreMessageCallbackT store_callback,
|
||||
IntraProcessManagerSharedPtr ipm,
|
||||
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();
|
||||
|
||||
using IntraProcessManagerWeakPtr =
|
||||
std::weak_ptr<rclcpp::intra_process_manager::IntraProcessManager>;
|
||||
bool intra_process_is_enabled_;
|
||||
IntraProcessManagerWeakPtr weak_ipm_;
|
||||
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
|
||||
@@ -201,6 +50,7 @@ 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>)
|
||||
|
||||
@@ -208,6 +58,7 @@ 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,
|
||||
@@ -217,112 +68,99 @@ 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)
|
||||
{
|
||||
bool inter_process_subscriptions_exist =
|
||||
get_subscription_count() > get_intra_process_subscription_count();
|
||||
if (!intra_process_is_enabled_ || inter_process_subscriptions_exist) {
|
||||
if (!intra_process_is_enabled_) {
|
||||
this->do_inter_process_publish(msg.get());
|
||||
return;
|
||||
}
|
||||
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");
|
||||
}
|
||||
// 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);
|
||||
} else {
|
||||
// Always destroy the message, even if we don't consume it, for consistency.
|
||||
msg.reset();
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
// 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<MessageT> & msg)
|
||||
publish(const 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(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);
|
||||
publish(*msg);
|
||||
}
|
||||
|
||||
virtual void
|
||||
publish(const MessageT & msg)
|
||||
{
|
||||
// Avoid allocating when not using intra process.
|
||||
if (!store_intra_process_message_) {
|
||||
if (!intra_process_is_enabled_) {
|
||||
// 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_);
|
||||
return this->publish(unique_msg);
|
||||
this->publish(std::move(unique_msg));
|
||||
}
|
||||
|
||||
// Skip deprecated attribute in windows, as it raise a warning in template specialization.
|
||||
#if !defined(_WIN32)
|
||||
[[deprecated(
|
||||
"Use publish(*msg). Check against nullptr before calling if necessary.")]]
|
||||
#endif
|
||||
virtual void
|
||||
publish(const MessageT * msg)
|
||||
{
|
||||
@@ -333,22 +171,31 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
publish(const rcl_serialized_message_t * serialized_msg)
|
||||
publish(const rcl_serialized_message_t & 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");
|
||||
}
|
||||
return this->do_serialized_publish(&serialized_msg);
|
||||
}
|
||||
|
||||
// Skip deprecated attribute in windows, as it raise a warning in template specialization.
|
||||
#if !defined(_WIN32)
|
||||
[[deprecated(
|
||||
"Use publish(*serialized_msg). Check against nullptr before calling if necessary.")]]
|
||||
#endif
|
||||
void
|
||||
publish(const rcl_serialized_message_t * serialized_msg)
|
||||
{
|
||||
return this->do_serialized_publish(serialized_msg);
|
||||
}
|
||||
|
||||
// Skip deprecated attribute in windows, as it raise a warning in template specialization.
|
||||
#if !defined(_WIN32)
|
||||
[[deprecated(
|
||||
"Use publish(*serialized_msg). Check against nullptr before calling if necessary.")]]
|
||||
#endif
|
||||
void
|
||||
publish(std::shared_ptr<const rcl_serialized_message_t> serialized_msg)
|
||||
{
|
||||
return this->publish(serialized_msg.get());
|
||||
return this->do_serialized_publish(serialized_msg.get());
|
||||
}
|
||||
|
||||
std::shared_ptr<MessageAlloc> get_allocator() const
|
||||
@@ -360,7 +207,7 @@ protected:
|
||||
void
|
||||
do_inter_process_publish(const MessageT * msg)
|
||||
{
|
||||
auto status = rcl_publish(&publisher_handle_, msg);
|
||||
auto status = rcl_publish(&publisher_handle_, msg, nullptr);
|
||||
if (RCL_RET_PUBLISHER_INVALID == status) {
|
||||
rcl_reset_error(); // next call will reset error message if not context
|
||||
if (rcl_publisher_is_valid_except_context(&publisher_handle_)) {
|
||||
@@ -376,6 +223,77 @@ 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_;
|
||||
|
||||
232
rclcpp/include/rclcpp/publisher_base.hpp
Normal file
232
rclcpp/include/rclcpp/publisher_base.hpp
Normal file
@@ -0,0 +1,232 @@
|
||||
// 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_
|
||||
@@ -49,94 +49,38 @@ struct PublisherFactory
|
||||
rclcpp::PublisherBase::SharedPtr(
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic_name,
|
||||
rcl_publisher_options_t & publisher_options)>;
|
||||
const 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(std::shared_ptr<Alloc> allocator)
|
||||
create_publisher_factory(
|
||||
const PublisherEventCallbacks & event_callbacks,
|
||||
std::shared_ptr<Alloc> allocator)
|
||||
{
|
||||
PublisherFactory factory;
|
||||
|
||||
// factory function that creates a MessageT specific PublisherT
|
||||
factory.create_typed_publisher =
|
||||
[allocator](
|
||||
[event_callbacks, allocator](
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic_name,
|
||||
rcl_publisher_options_t & publisher_options) -> std::shared_ptr<PublisherT>
|
||||
const 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());
|
||||
publisher_options.allocator = allocator::get_rcl_allocator<MessageT>(*message_alloc.get());
|
||||
options_copy.allocator = allocator::get_rcl_allocator<MessageT>(*message_alloc.get());
|
||||
|
||||
return std::make_shared<PublisherT>(node_base, topic_name, publisher_options, message_alloc);
|
||||
};
|
||||
|
||||
// function to add a publisher to the intra process manager
|
||||
factory.add_publisher_to_intra_process_manager =
|
||||
[](
|
||||
rclcpp::intra_process_manager::IntraProcessManager * ipm,
|
||||
rclcpp::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 std::make_shared<PublisherT>(
|
||||
node_base,
|
||||
topic_name,
|
||||
options_copy,
|
||||
event_callbacks,
|
||||
message_alloc);
|
||||
};
|
||||
|
||||
// return the factory now that it is populated
|
||||
|
||||
@@ -19,22 +19,56 @@
|
||||
#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
|
||||
{
|
||||
|
||||
/// Structure containing optional configuration for Publishers.
|
||||
template<typename Allocator>
|
||||
struct PublisherOptionsWithAllocator
|
||||
/// Non-templated part of PublisherOptionsWithAllocator<Allocator>.
|
||||
struct PublisherOptionsBase
|
||||
{
|
||||
/// The quality of service profile to pass on to the rmw implementation.
|
||||
rmw_qos_profile_t qos_profile = rmw_qos_profile_default;
|
||||
/// Optional custom allocator.
|
||||
std::shared_ptr<Allocator> allocator = nullptr;
|
||||
/// 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>>;
|
||||
|
||||
206
rclcpp/include/rclcpp/qos.hpp
Normal file
206
rclcpp/include/rclcpp/qos.hpp
Normal file
@@ -0,0 +1,206 @@
|
||||
// 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.
|
||||
/**
|
||||
* Note that this cannot be named `volatile` because it is a C++ keyword.
|
||||
*/
|
||||
QoS &
|
||||
durability_volatile();
|
||||
|
||||
/// 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_
|
||||
126
rclcpp/include/rclcpp/qos_event.hpp
Normal file
126
rclcpp/include/rclcpp/qos_event.hpp
Normal file
@@ -0,0 +1,126 @@
|
||||
// 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_
|
||||
@@ -156,6 +156,16 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// Default constructor.
|
||||
/**
|
||||
* The constructor for a Service is almost never called directly.
|
||||
* Instead, services should be instantiated through the function
|
||||
* rclcpp::create_service().
|
||||
*
|
||||
* \param[in] node_handle NodeBaseInterface pointer that is used in part of the setup.
|
||||
* \param[in] service_handle service handle.
|
||||
* \param[in] any_callback User defined callback to call when a client request is received.
|
||||
*/
|
||||
Service(
|
||||
std::shared_ptr<rcl_node_t> node_handle,
|
||||
std::shared_ptr<rcl_service_t> service_handle,
|
||||
@@ -174,6 +184,16 @@ public:
|
||||
service_handle_ = service_handle;
|
||||
}
|
||||
|
||||
/// Default constructor.
|
||||
/**
|
||||
* The constructor for a Service is almost never called directly.
|
||||
* Instead, services should be instantiated through the function
|
||||
* rclcpp::create_service().
|
||||
*
|
||||
* \param[in] node_handle NodeBaseInterface pointer that is used in part of the setup.
|
||||
* \param[in] service_handle service handle.
|
||||
* \param[in] any_callback User defined callback to call when a client request is received.
|
||||
*/
|
||||
Service(
|
||||
std::shared_ptr<rcl_node_t> node_handle,
|
||||
rcl_service_t * service_handle,
|
||||
|
||||
@@ -150,7 +150,7 @@ public:
|
||||
);
|
||||
}
|
||||
|
||||
bool collect_entities(const WeakNodeVector & weak_nodes)
|
||||
bool collect_entities(const WeakNodeList & weak_nodes)
|
||||
{
|
||||
bool has_invalid_weak_nodes = false;
|
||||
for (auto & weak_node : weak_nodes) {
|
||||
@@ -265,7 +265,7 @@ public:
|
||||
virtual void
|
||||
get_next_subscription(
|
||||
executor::AnyExecutable & any_exec,
|
||||
const WeakNodeVector & weak_nodes)
|
||||
const WeakNodeList & weak_nodes)
|
||||
{
|
||||
auto it = subscription_handles_.begin();
|
||||
while (it != subscription_handles_.end()) {
|
||||
@@ -309,7 +309,7 @@ public:
|
||||
virtual void
|
||||
get_next_service(
|
||||
executor::AnyExecutable & any_exec,
|
||||
const WeakNodeVector & weak_nodes)
|
||||
const WeakNodeList & weak_nodes)
|
||||
{
|
||||
auto it = service_handles_.begin();
|
||||
while (it != service_handles_.end()) {
|
||||
@@ -342,7 +342,7 @@ public:
|
||||
}
|
||||
|
||||
virtual void
|
||||
get_next_client(executor::AnyExecutable & any_exec, const WeakNodeVector & weak_nodes)
|
||||
get_next_client(executor::AnyExecutable & any_exec, const WeakNodeList & weak_nodes)
|
||||
{
|
||||
auto it = client_handles_.begin();
|
||||
while (it != client_handles_.end()) {
|
||||
@@ -375,7 +375,7 @@ public:
|
||||
}
|
||||
|
||||
virtual void
|
||||
get_next_waitable(executor::AnyExecutable & any_exec, const WeakNodeVector & weak_nodes)
|
||||
get_next_waitable(executor::AnyExecutable & any_exec, const WeakNodeList & weak_nodes)
|
||||
{
|
||||
auto it = waitable_handles_.begin();
|
||||
while (it != waitable_handles_.end()) {
|
||||
@@ -430,6 +430,15 @@ 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();
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/subscription.h"
|
||||
@@ -32,11 +34,15 @@
|
||||
#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
|
||||
{
|
||||
@@ -46,122 +52,6 @@ namespace node_interfaces
|
||||
class NodeTopicsInterface;
|
||||
} // namespace node_interfaces
|
||||
|
||||
namespace intra_process_manager
|
||||
{
|
||||
/**
|
||||
* NOTE(ivanpauno): IntraProcessManager is forward declared here, avoiding a circular inclusion between intra_process_manager.hpp and publisher.hpp.
|
||||
* SharedPtr and WeakPtr of the IntraProcessManager are defined again here, to avoid a warning for accessing a member of a forward declared class.
|
||||
*/
|
||||
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;
|
||||
|
||||
/// 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;
|
||||
|
||||
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_;
|
||||
|
||||
using IntraProcessManagerWeakPtr =
|
||||
std::weak_ptr<rclcpp::intra_process_manager::IntraProcessManager>;
|
||||
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_;
|
||||
};
|
||||
|
||||
/// Subscription implementation, templated on the type of message this subscription receives.
|
||||
template<
|
||||
typename CallbackMessageT,
|
||||
@@ -174,6 +64,7 @@ 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)
|
||||
@@ -195,6 +86,7 @@ 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())
|
||||
@@ -205,10 +97,17 @@ public:
|
||||
subscription_options,
|
||||
rclcpp::subscription_traits::is_serialized_subscription_argument<CallbackMessageT>::value),
|
||||
any_callback_(callback),
|
||||
message_memory_strategy_(memory_strategy),
|
||||
get_intra_process_message_callback_(nullptr),
|
||||
matches_any_intra_process_publishers_(nullptr)
|
||||
{}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// Support dynamically setting the message memory strategy.
|
||||
/**
|
||||
@@ -238,12 +137,10 @@ public:
|
||||
|
||||
void handle_message(std::shared_ptr<void> & message, const rmw_message_info_t & message_info)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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);
|
||||
@@ -266,89 +163,118 @@ public:
|
||||
rcl_interfaces::msg::IntraProcessMessage & ipm,
|
||||
const rmw_message_info_t & message_info)
|
||||
{
|
||||
if (!get_intra_process_message_callback_) {
|
||||
if (!use_intra_process_) {
|
||||
// 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;
|
||||
}
|
||||
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?
|
||||
|
||||
if (!matches_any_intra_process_publishers(&message_info.publisher_gid)) {
|
||||
// This intra-process message has not been created by a publisher from this context.
|
||||
// we should ignore this copy of the message.
|
||||
return;
|
||||
}
|
||||
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.
|
||||
// TODO(ivanpauno): This can be moved to the base class. No reason to be here.
|
||||
// Also get_intra_process_message_callback_ and matches_any_intra_process_publishers_.
|
||||
void setup_intra_process(
|
||||
uint64_t intra_process_subscription_id,
|
||||
GetMessageCallbackType get_message_callback,
|
||||
MatchesAnyPublishersCallbackType matches_any_publisher_callback,
|
||||
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));
|
||||
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 can happen when having two nodes in different process both using intraprocess
|
||||
// communication. It could happen too if the publisher no longer exists or the requested
|
||||
// message is not longer being stored.
|
||||
// TODO(ivanpauno): Print a warn message in the last two cases described above,
|
||||
// but not in the first one.
|
||||
return;
|
||||
}
|
||||
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret, "could not create intra process subscription");
|
||||
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 can happen when having two nodes in different process both using intraprocess
|
||||
// communication. It could happen too if the publisher no longer exists or the requested
|
||||
// message is not longer being stored.
|
||||
// TODO(ivanpauno): Print a warn message in the last two cases described above,
|
||||
// but not in the first one.
|
||||
return;
|
||||
}
|
||||
any_callback_.dispatch_intra_process(std::move(msg), message_info);
|
||||
}
|
||||
|
||||
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;
|
||||
weak_ipm_ = weak_ipm;
|
||||
use_intra_process_ = true;
|
||||
}
|
||||
|
||||
/// Implemenation detail.
|
||||
const std::shared_ptr<rcl_subscription_t>
|
||||
get_intra_process_subscription_handle() const
|
||||
{
|
||||
if (!get_intra_process_message_callback_) {
|
||||
if (!use_intra_process_) {
|
||||
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_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
189
rclcpp/include/rclcpp/subscription_base.hpp
Normal file
189
rclcpp/include/rclcpp/subscription_base.hpp
Normal file
@@ -0,0 +1,189 @@
|
||||
// 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_
|
||||
@@ -51,7 +51,7 @@ struct SubscriptionFactory
|
||||
rclcpp::SubscriptionBase::SharedPtr(
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic_name,
|
||||
rcl_subscription_options_t & subscription_options)>;
|
||||
const rcl_subscription_options_t & subscription_options)>;
|
||||
|
||||
SubscriptionFactoryFunction create_typed_subscription;
|
||||
|
||||
@@ -65,7 +65,12 @@ struct SubscriptionFactory
|
||||
SetupIntraProcessFunction setup_intra_process;
|
||||
};
|
||||
|
||||
/// Return a SubscriptionFactory with functions for creating a SubscriptionT<MessageT, Alloc>.
|
||||
/// Return a SubscriptionFactory setup to create a SubscriptionT<MessageT, AllocatorT>.
|
||||
/**
|
||||
* \param[in] callback The user-defined callback function to receive a message
|
||||
* \param[in] options Additional options for the creation of the Subscription.
|
||||
* \param[in] msg_mem_strat The message memory strategy to use for allocating messages.
|
||||
*/
|
||||
template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
@@ -75,6 +80,7 @@ template<
|
||||
SubscriptionFactory
|
||||
create_subscription_factory(
|
||||
CallbackT && callback,
|
||||
const SubscriptionEventCallbacks & event_callbacks,
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT, Alloc>::SharedPtr
|
||||
msg_mem_strat,
|
||||
@@ -91,13 +97,14 @@ create_subscription_factory(
|
||||
|
||||
// factory function that creates a MessageT specific SubscriptionT
|
||||
factory.create_typed_subscription =
|
||||
[allocator, msg_mem_strat, any_subscription_callback, message_alloc](
|
||||
[allocator, msg_mem_strat, any_subscription_callback, event_callbacks, message_alloc](
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic_name,
|
||||
rcl_subscription_options_t & subscription_options
|
||||
const rcl_subscription_options_t & subscription_options
|
||||
) -> rclcpp::SubscriptionBase::SharedPtr
|
||||
{
|
||||
subscription_options.allocator =
|
||||
auto options_copy = subscription_options;
|
||||
options_copy.allocator =
|
||||
rclcpp::allocator::get_rcl_allocator<CallbackMessageT>(*message_alloc.get());
|
||||
|
||||
using rclcpp::Subscription;
|
||||
@@ -107,71 +114,14 @@ create_subscription_factory(
|
||||
node_base->get_shared_rcl_node_handle(),
|
||||
*rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>(),
|
||||
topic_name,
|
||||
subscription_options,
|
||||
options_copy,
|
||||
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,
|
||||
weak_ipm,
|
||||
intra_process_options
|
||||
);
|
||||
};
|
||||
// end definition of factory function to setup intra process
|
||||
|
||||
// return the factory now that it is populated
|
||||
return factory;
|
||||
}
|
||||
|
||||
@@ -19,28 +19,59 @@
|
||||
#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
|
||||
{
|
||||
|
||||
/// Structure containing optional configuration for Subscriptions.
|
||||
template<typename Allocator>
|
||||
struct SubscriptionOptionsWithAllocator
|
||||
/// Non-template base class for subscription options.
|
||||
struct SubscriptionOptionsBase
|
||||
{
|
||||
/// The quality of service profile to pass on to the rmw implementation.
|
||||
rmw_qos_profile_t qos_profile = rmw_qos_profile_default;
|
||||
/// 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;
|
||||
/// Optional custom allocator.
|
||||
std::shared_ptr<Allocator> allocator = 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
|
||||
|
||||
@@ -18,9 +18,13 @@
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/function_traits.hpp"
|
||||
#include "rcl/types.h"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
class QoS;
|
||||
|
||||
namespace subscription_traits
|
||||
{
|
||||
|
||||
@@ -69,7 +73,20 @@ template<typename MessageT, typename Deleter>
|
||||
struct extract_message_type<std::unique_ptr<MessageT, Deleter>>: extract_message_type<MessageT>
|
||||
{};
|
||||
|
||||
template<typename CallbackT>
|
||||
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>
|
||||
>
|
||||
struct has_message_type : extract_message_type<
|
||||
typename rclcpp::function_traits::function_traits<CallbackT>::template argument_type<0>>
|
||||
{};
|
||||
|
||||
@@ -34,17 +34,32 @@ public:
|
||||
RCLCPP_PUBLIC
|
||||
Time(int32_t seconds, uint32_t nanoseconds, rcl_clock_type_t clock_type = RCL_SYSTEM_TIME);
|
||||
|
||||
/// Time constructor
|
||||
/**
|
||||
* \param nanoseconds since time epoch
|
||||
* \param clock_type clock type
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
explicit Time(int64_t nanoseconds = 0, rcl_clock_type_t clock = RCL_SYSTEM_TIME);
|
||||
explicit Time(int64_t nanoseconds = 0, rcl_clock_type_t clock_type = RCL_SYSTEM_TIME);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
Time(const Time & rhs);
|
||||
|
||||
/// Time constructor
|
||||
/**
|
||||
* \param time_msg builtin_interfaces time message to copy
|
||||
* \param clock_type clock type
|
||||
* \throws std::runtime_error if seconds are negative
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
Time(
|
||||
const builtin_interfaces::msg::Time & time_msg,
|
||||
rcl_clock_type_t ros_time = RCL_ROS_TIME);
|
||||
rcl_clock_type_t clock_type = RCL_ROS_TIME);
|
||||
|
||||
/// Time constructor
|
||||
/**
|
||||
* \param time_point rcl_time_point_t structure to copy
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
explicit Time(const rcl_time_point_t & time_point);
|
||||
|
||||
@@ -58,6 +73,12 @@ public:
|
||||
Time &
|
||||
operator=(const Time & rhs);
|
||||
|
||||
/**
|
||||
* Assign Time from a builtin_interfaces::msg::Time instance.
|
||||
* The clock_type will be reset to RCL_ROS_TIME.
|
||||
* Equivalent to *this = Time(time_msg, RCL_ROS_TIME).
|
||||
* \throws std::runtime_error if seconds are negative
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
Time &
|
||||
operator=(const builtin_interfaces::msg::Time & time_msg);
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
#include "rcl_interfaces/msg/parameter_event.hpp"
|
||||
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/parameter_client.hpp"
|
||||
#include "rclcpp/parameter_events_filter.hpp"
|
||||
|
||||
|
||||
namespace rclcpp
|
||||
@@ -100,9 +98,6 @@ private:
|
||||
// Destroy the subscription for the clock topic
|
||||
void destroy_clock_sub();
|
||||
|
||||
// Parameter Client pointer
|
||||
std::shared_ptr<rclcpp::AsyncParametersClient> parameter_client_;
|
||||
|
||||
// Parameter Event subscription
|
||||
using ParamMessageT = rcl_interfaces::msg::ParameterEvent;
|
||||
using ParamSubscriptionT = rclcpp::Subscription<ParamMessageT, Alloc>;
|
||||
|
||||
@@ -126,6 +126,7 @@ public:
|
||||
* \param[in] clock The clock providing the current time.
|
||||
* \param[in] period The interval at which the timer fires.
|
||||
* \param[in] callback User-specified callback function.
|
||||
* \param[in] context custom context to be used.
|
||||
*/
|
||||
explicit GenericTimer(
|
||||
Clock::SharedPtr clock, std::chrono::nanoseconds period, FunctorT && callback,
|
||||
|
||||
@@ -61,6 +61,17 @@ 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.
|
||||
@@ -88,6 +99,7 @@ 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
|
||||
@@ -107,7 +119,7 @@ public:
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
bool
|
||||
is_ready(rcl_wait_set_t *) = 0;
|
||||
is_ready(rcl_wait_set_t * wait_set) = 0;
|
||||
|
||||
/// Execute any entities of the Waitable that are ready.
|
||||
/**
|
||||
|
||||
@@ -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.1</version>
|
||||
<version>0.7.16</version>
|
||||
<description>The ROS client library in C++.</description>
|
||||
<maintainer email="dthomas@osrfoundation.org">Dirk Thomas</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
@@ -14,14 +14,6 @@
|
||||
|
||||
#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"
|
||||
@@ -30,8 +22,8 @@ namespace rclcpp
|
||||
{
|
||||
|
||||
JumpHandler::JumpHandler(
|
||||
std::function<void()> pre_callback,
|
||||
std::function<void(const rcl_time_jump_t &)> post_callback,
|
||||
pre_callback_t pre_callback,
|
||||
post_callback_t post_callback,
|
||||
const rcl_jump_threshold_t & threshold)
|
||||
: pre_callback(pre_callback),
|
||||
post_callback(post_callback),
|
||||
@@ -43,8 +35,7 @@ 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) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(
|
||||
ret, "could not get current time stamp");
|
||||
exceptions::throw_from_rcl_error(ret, "failed to initialize rcl clock");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,8 +54,7 @@ Clock::now()
|
||||
|
||||
auto ret = rcl_clock_get_now(&rcl_clock_, &now.rcl_time_.nanoseconds);
|
||||
if (ret != RCL_RET_OK) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(
|
||||
ret, "could not get current time stamp");
|
||||
exceptions::throw_from_rcl_error(ret, "could not get current time stamp");
|
||||
}
|
||||
|
||||
return now;
|
||||
@@ -78,23 +68,23 @@ Clock::ros_time_is_active()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_enabled;
|
||||
bool is_enabled = false;
|
||||
auto ret = rcl_is_enabled_ros_time_override(&rcl_clock_, &is_enabled);
|
||||
if (ret != RCL_RET_OK) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(
|
||||
exceptions::throw_from_rcl_error(
|
||||
ret, "Failed to check ros_time_override_status");
|
||||
}
|
||||
return is_enabled;
|
||||
}
|
||||
|
||||
rcl_clock_t *
|
||||
Clock::get_clock_handle()
|
||||
Clock::get_clock_handle() noexcept
|
||||
{
|
||||
return &rcl_clock_;
|
||||
}
|
||||
|
||||
rcl_clock_type_t
|
||||
Clock::get_clock_type()
|
||||
Clock::get_clock_type() const noexcept
|
||||
{
|
||||
return rcl_clock_.type;
|
||||
}
|
||||
@@ -105,7 +95,10 @@ Clock::on_time_jump(
|
||||
bool before_jump,
|
||||
void * user_data)
|
||||
{
|
||||
rclcpp::JumpHandler * handler = static_cast<rclcpp::JumpHandler *>(user_data);
|
||||
const auto * handler = static_cast<JumpHandler *>(user_data);
|
||||
if (nullptr == handler) {
|
||||
return;
|
||||
}
|
||||
if (before_jump && handler->pre_callback) {
|
||||
handler->pre_callback();
|
||||
} else if (!before_jump && handler->post_callback) {
|
||||
@@ -113,36 +106,30 @@ Clock::on_time_jump(
|
||||
}
|
||||
}
|
||||
|
||||
rclcpp::JumpHandler::SharedPtr
|
||||
JumpHandler::SharedPtr
|
||||
Clock::create_jump_callback(
|
||||
std::function<void()> pre_callback,
|
||||
std::function<void(const rcl_time_jump_t &)> post_callback,
|
||||
JumpHandler::pre_callback_t pre_callback,
|
||||
JumpHandler::post_callback_t post_callback,
|
||||
const rcl_jump_threshold_t & threshold)
|
||||
{
|
||||
// Allocate a new jump handler
|
||||
auto handler = new rclcpp::JumpHandler(pre_callback, post_callback, threshold);
|
||||
JumpHandler::UniquePtr handler(new JumpHandler(pre_callback, post_callback, threshold));
|
||||
if (nullptr == handler) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(RCL_RET_BAD_ALLOC, "Failed to allocate jump handler");
|
||||
throw std::bad_alloc{};
|
||||
}
|
||||
|
||||
// Try to add the jump callback to the clock
|
||||
rcl_ret_t ret = rcl_clock_add_jump_callback(&rcl_clock_, threshold,
|
||||
rclcpp::Clock::on_time_jump, handler);
|
||||
Clock::on_time_jump, handler.get());
|
||||
if (RCL_RET_OK != ret) {
|
||||
delete handler;
|
||||
handler = nullptr;
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to add time jump callback");
|
||||
}
|
||||
|
||||
if (nullptr == handler) {
|
||||
// imposible to reach here; added to make cppcheck happy
|
||||
return nullptr;
|
||||
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
|
||||
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,
|
||||
// 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,
|
||||
handler);
|
||||
delete handler;
|
||||
handler = NULL;
|
||||
|
||||
@@ -47,16 +47,14 @@ Duration::Duration(std::chrono::nanoseconds nanoseconds)
|
||||
rcl_duration_.nanoseconds = nanoseconds.count();
|
||||
}
|
||||
|
||||
Duration::Duration(const Duration & rhs)
|
||||
{
|
||||
rcl_duration_.nanoseconds = rhs.rcl_duration_.nanoseconds;
|
||||
}
|
||||
Duration::Duration(const Duration & rhs) = default;
|
||||
|
||||
Duration::Duration(
|
||||
const builtin_interfaces::msg::Duration & duration_msg)
|
||||
{
|
||||
rcl_duration_.nanoseconds = RCL_S_TO_NS(static_cast<uint64_t>(duration_msg.sec));
|
||||
rcl_duration_.nanoseconds += duration_msg.nanosec;
|
||||
rcl_duration_.nanoseconds =
|
||||
RCL_S_TO_NS(static_cast<rcl_duration_value_t>(duration_msg.sec));
|
||||
rcl_duration_.nanoseconds += static_cast<rcl_duration_value_t>(duration_msg.nanosec);
|
||||
}
|
||||
|
||||
Duration::Duration(const rcl_duration_t & duration)
|
||||
@@ -65,31 +63,28 @@ Duration::Duration(const rcl_duration_t & duration)
|
||||
// noop
|
||||
}
|
||||
|
||||
Duration::~Duration()
|
||||
{
|
||||
}
|
||||
|
||||
Duration::operator builtin_interfaces::msg::Duration() const
|
||||
{
|
||||
builtin_interfaces::msg::Duration msg_duration;
|
||||
msg_duration.sec = static_cast<std::int32_t>(RCL_NS_TO_S(rcl_duration_.nanoseconds));
|
||||
msg_duration.nanosec =
|
||||
static_cast<std::uint32_t>(rcl_duration_.nanoseconds % (1000 * 1000 * 1000));
|
||||
constexpr rcl_duration_value_t kDivisor = RCL_S_TO_NS(1);
|
||||
const auto result = std::div(rcl_duration_.nanoseconds, kDivisor);
|
||||
if (result.rem >= 0) {
|
||||
msg_duration.sec = static_cast<std::int32_t>(result.quot);
|
||||
msg_duration.nanosec = static_cast<std::uint32_t>(result.rem);
|
||||
} else {
|
||||
msg_duration.sec = static_cast<std::int32_t>(result.quot - 1);
|
||||
msg_duration.nanosec = static_cast<std::uint32_t>(kDivisor + result.rem);
|
||||
}
|
||||
return msg_duration;
|
||||
}
|
||||
|
||||
Duration &
|
||||
Duration::operator=(const Duration & rhs)
|
||||
{
|
||||
rcl_duration_.nanoseconds = rhs.rcl_duration_.nanoseconds;
|
||||
return *this;
|
||||
}
|
||||
Duration::operator=(const Duration & rhs) = default;
|
||||
|
||||
Duration &
|
||||
Duration::operator=(const builtin_interfaces::msg::Duration & duration_msg)
|
||||
{
|
||||
rcl_duration_.nanoseconds = RCL_S_TO_NS(static_cast<int64_t>(duration_msg.sec));
|
||||
rcl_duration_.nanoseconds += duration_msg.nanosec;
|
||||
*this = Duration(duration_msg);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -99,6 +94,12 @@ Duration::operator==(const rclcpp::Duration & rhs) const
|
||||
return rcl_duration_.nanoseconds == rhs.rcl_duration_.nanoseconds;
|
||||
}
|
||||
|
||||
bool
|
||||
Duration::operator!=(const rclcpp::Duration & rhs) const
|
||||
{
|
||||
return rcl_duration_.nanoseconds != rhs.rcl_duration_.nanoseconds;
|
||||
}
|
||||
|
||||
bool
|
||||
Duration::operator<(const rclcpp::Duration & rhs) const
|
||||
{
|
||||
@@ -126,15 +127,15 @@ Duration::operator>(const rclcpp::Duration & rhs) const
|
||||
void
|
||||
bounds_check_duration_sum(int64_t lhsns, int64_t rhsns, uint64_t max)
|
||||
{
|
||||
auto abs_lhs = (uint64_t)std::abs(lhsns);
|
||||
auto abs_rhs = (uint64_t)std::abs(rhsns);
|
||||
auto abs_lhs = static_cast<uint64_t>(std::abs(lhsns));
|
||||
auto abs_rhs = static_cast<uint64_t>(std::abs(rhsns));
|
||||
|
||||
if (lhsns > 0 && rhsns > 0) {
|
||||
if (abs_lhs + abs_rhs > (uint64_t) max) {
|
||||
if (abs_lhs + abs_rhs > max) {
|
||||
throw std::overflow_error("addition leads to int64_t overflow");
|
||||
}
|
||||
} else if (lhsns < 0 && rhsns < 0) {
|
||||
if (abs_lhs + abs_rhs > (uint64_t) max) {
|
||||
if (abs_lhs + abs_rhs > max) {
|
||||
throw std::underflow_error("addition leads to int64_t underflow");
|
||||
}
|
||||
}
|
||||
@@ -154,15 +155,15 @@ Duration::operator+(const rclcpp::Duration & rhs) const
|
||||
void
|
||||
bounds_check_duration_difference(int64_t lhsns, int64_t rhsns, uint64_t max)
|
||||
{
|
||||
auto abs_lhs = (uint64_t)std::abs(lhsns);
|
||||
auto abs_rhs = (uint64_t)std::abs(rhsns);
|
||||
auto abs_lhs = static_cast<uint64_t>(std::abs(lhsns));
|
||||
auto abs_rhs = static_cast<uint64_t>(std::abs(rhsns));
|
||||
|
||||
if (lhsns > 0 && rhsns < 0) {
|
||||
if (abs_lhs + abs_rhs > (uint64_t) max) {
|
||||
if (abs_lhs + abs_rhs > max) {
|
||||
throw std::overflow_error("duration subtraction leads to int64_t overflow");
|
||||
}
|
||||
} else if (lhsns < 0 && rhsns > 0) {
|
||||
if (abs_lhs + abs_rhs > (uint64_t) max) {
|
||||
if (abs_lhs + abs_rhs > max) {
|
||||
throw std::underflow_error("duration subtraction leads to int64_t underflow");
|
||||
}
|
||||
}
|
||||
@@ -185,8 +186,10 @@ bounds_check_duration_scale(int64_t dns, double scale, uint64_t max)
|
||||
{
|
||||
auto abs_dns = static_cast<uint64_t>(std::abs(dns));
|
||||
auto abs_scale = std::abs(scale);
|
||||
|
||||
if (abs_scale > 1.0 && abs_dns > static_cast<uint64_t>(max / abs_scale)) {
|
||||
if (abs_scale > 1.0 &&
|
||||
abs_dns >
|
||||
static_cast<uint64_t>(static_cast<long double>(max) / static_cast<long double>(abs_scale)))
|
||||
{
|
||||
if ((dns > 0 && scale > 0) || (dns < 0 && scale < 0)) {
|
||||
throw std::overflow_error("duration scaling leads to int64_t overflow");
|
||||
} else {
|
||||
@@ -205,7 +208,9 @@ Duration::operator*(double scale) const
|
||||
this->rcl_duration_.nanoseconds,
|
||||
scale,
|
||||
std::numeric_limits<rcl_duration_value_t>::max());
|
||||
return Duration(static_cast<rcl_duration_value_t>(rcl_duration_.nanoseconds * scale));
|
||||
long double scale_ld = static_cast<long double>(scale);
|
||||
return Duration(static_cast<rcl_duration_value_t>(
|
||||
static_cast<long double>(rcl_duration_.nanoseconds) * scale_ld));
|
||||
}
|
||||
|
||||
rcl_duration_value_t
|
||||
@@ -226,4 +231,19 @@ Duration::seconds() const
|
||||
return std::chrono::duration<double>(std::chrono::nanoseconds(rcl_duration_.nanoseconds)).count();
|
||||
}
|
||||
|
||||
rmw_time_t
|
||||
Duration::to_rmw_time() const
|
||||
{
|
||||
if (rcl_duration_.nanoseconds < 0) {
|
||||
throw std::runtime_error("rmw_time_t cannot be negative");
|
||||
}
|
||||
|
||||
// reuse conversion logic from msg creation
|
||||
builtin_interfaces::msg::Duration msg = *this;
|
||||
rmw_time_t result;
|
||||
result.sec = static_cast<uint64_t>(msg.sec);
|
||||
result.nsec = static_cast<uint64_t>(msg.nanosec);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -60,7 +60,11 @@ 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, context_->get_rcl_context().get(), allocator);
|
||||
ret = rcl_wait_set_init(
|
||||
&wait_set_,
|
||||
0, 2, 0, 0, 0, 0,
|
||||
context_->get_rcl_context().get(),
|
||||
allocator);
|
||||
if (RCL_RET_OK != ret) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
@@ -87,6 +91,10 @@ Executor::~Executor()
|
||||
}
|
||||
}
|
||||
weak_nodes_.clear();
|
||||
for (auto & guard_condition : guard_conditions_) {
|
||||
memory_strategy_->remove_guard_condition(guard_condition);
|
||||
}
|
||||
guard_conditions_.clear();
|
||||
|
||||
// Finalize the wait set.
|
||||
if (rcl_wait_set_fini(&wait_set_) != RCL_RET_OK) {
|
||||
@@ -124,6 +132,7 @@ Executor::add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_pt
|
||||
}
|
||||
}
|
||||
weak_nodes_.push_back(node_ptr);
|
||||
guard_conditions_.push_back(node_ptr->get_notify_guard_condition());
|
||||
if (notify) {
|
||||
// Interrupt waiting to handle new node
|
||||
if (rcl_trigger_guard_condition(&interrupt_guard_condition_) != RCL_RET_OK) {
|
||||
@@ -131,6 +140,7 @@ Executor::add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_pt
|
||||
}
|
||||
}
|
||||
// Add the node's notify condition to the guard condition handles
|
||||
std::unique_lock<std::mutex> lock(memory_strategy_mutex_);
|
||||
memory_strategy_->add_guard_condition(node_ptr->get_notify_guard_condition());
|
||||
}
|
||||
|
||||
@@ -144,17 +154,21 @@ void
|
||||
Executor::remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify)
|
||||
{
|
||||
bool node_removed = false;
|
||||
weak_nodes_.erase(
|
||||
std::remove_if(
|
||||
weak_nodes_.begin(), weak_nodes_.end(),
|
||||
[&](rclcpp::node_interfaces::NodeBaseInterface::WeakPtr & i)
|
||||
{
|
||||
bool matched = (i.lock() == node_ptr);
|
||||
node_removed |= matched;
|
||||
return matched;
|
||||
{
|
||||
auto node_it = weak_nodes_.begin();
|
||||
auto gc_it = guard_conditions_.begin();
|
||||
while (node_it != weak_nodes_.end()) {
|
||||
bool matched = (node_it->lock() == node_ptr);
|
||||
if (matched) {
|
||||
node_it = weak_nodes_.erase(node_it);
|
||||
gc_it = guard_conditions_.erase(gc_it);
|
||||
node_removed = true;
|
||||
} else {
|
||||
++node_it;
|
||||
++gc_it;
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
std::atomic_bool & has_executor = node_ptr->get_associated_with_executor_atomic();
|
||||
has_executor.store(false);
|
||||
if (notify) {
|
||||
@@ -165,6 +179,7 @@ Executor::remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node
|
||||
}
|
||||
}
|
||||
}
|
||||
std::unique_lock<std::mutex> lock(memory_strategy_mutex_);
|
||||
memory_strategy_->remove_guard_condition(node_ptr->get_notify_guard_condition());
|
||||
}
|
||||
|
||||
@@ -219,7 +234,7 @@ Executor::spin_some(std::chrono::nanoseconds max_duration)
|
||||
throw std::runtime_error("spin_some() called while already spinning");
|
||||
}
|
||||
RCLCPP_SCOPE_EXIT(this->spinning.store(false); );
|
||||
while (spinning.load() && max_duration_not_elapsed()) {
|
||||
while (rclcpp::ok(context_) && spinning.load() && max_duration_not_elapsed()) {
|
||||
AnyExecutable any_exec;
|
||||
if (get_next_executable(any_exec, std::chrono::milliseconds::zero())) {
|
||||
execute_any_executable(any_exec);
|
||||
@@ -229,6 +244,15 @@ Executor::spin_some(std::chrono::nanoseconds max_duration)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Executor::spin_once_impl(std::chrono::nanoseconds timeout)
|
||||
{
|
||||
AnyExecutable any_exec;
|
||||
if (get_next_executable(any_exec, timeout)) {
|
||||
execute_any_executable(any_exec);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Executor::spin_once(std::chrono::nanoseconds timeout)
|
||||
{
|
||||
@@ -236,10 +260,7 @@ Executor::spin_once(std::chrono::nanoseconds timeout)
|
||||
throw std::runtime_error("spin_once() called while already spinning");
|
||||
}
|
||||
RCLCPP_SCOPE_EXIT(this->spinning.store(false); );
|
||||
AnyExecutable any_exec;
|
||||
if (get_next_executable(any_exec, timeout)) {
|
||||
execute_any_executable(any_exec);
|
||||
}
|
||||
spin_once_impl(timeout);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -304,7 +325,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);
|
||||
serialized_msg.get(), &message_info, nullptr);
|
||||
if (RCL_RET_OK == ret) {
|
||||
auto void_serialized_msg = std::static_pointer_cast<void>(serialized_msg);
|
||||
subscription->handle_message(void_serialized_msg, message_info);
|
||||
@@ -320,7 +341,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);
|
||||
message.get(), &message_info, nullptr);
|
||||
if (RCL_RET_OK == ret) {
|
||||
subscription->handle_message(message, message_info);
|
||||
} else if (RCL_RET_SUBSCRIPTION_TAKE_FAILED != ret) {
|
||||
@@ -343,7 +364,8 @@ Executor::execute_intra_process_subscription(
|
||||
rcl_ret_t status = rcl_take(
|
||||
subscription->get_intra_process_subscription_handle().get(),
|
||||
&ipm,
|
||||
&message_info);
|
||||
&message_info,
|
||||
nullptr);
|
||||
|
||||
if (status == RCL_RET_OK) {
|
||||
message_info.from_intra_process = true;
|
||||
@@ -409,39 +431,47 @@ Executor::execute_client(
|
||||
void
|
||||
Executor::wait_for_work(std::chrono::nanoseconds timeout)
|
||||
{
|
||||
// Collect the subscriptions and timers to be waited on
|
||||
memory_strategy_->clear_handles();
|
||||
bool has_invalid_weak_nodes = memory_strategy_->collect_entities(weak_nodes_);
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(memory_strategy_mutex_);
|
||||
|
||||
// Clean up any invalid nodes, if they were detected
|
||||
if (has_invalid_weak_nodes) {
|
||||
weak_nodes_.erase(
|
||||
remove_if(
|
||||
weak_nodes_.begin(), weak_nodes_.end(),
|
||||
[](rclcpp::node_interfaces::NodeBaseInterface::WeakPtr i)
|
||||
{
|
||||
return i.expired();
|
||||
// Collect the subscriptions and timers to be waited on
|
||||
memory_strategy_->clear_handles();
|
||||
bool has_invalid_weak_nodes = memory_strategy_->collect_entities(weak_nodes_);
|
||||
|
||||
// Clean up any invalid nodes, if they were detected
|
||||
if (has_invalid_weak_nodes) {
|
||||
auto node_it = weak_nodes_.begin();
|
||||
auto gc_it = guard_conditions_.begin();
|
||||
while (node_it != weak_nodes_.end()) {
|
||||
if (node_it->expired()) {
|
||||
node_it = weak_nodes_.erase(node_it);
|
||||
memory_strategy_->remove_guard_condition(*gc_it);
|
||||
gc_it = guard_conditions_.erase(gc_it);
|
||||
} else {
|
||||
++node_it;
|
||||
++gc_it;
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
// clear wait set
|
||||
if (rcl_wait_set_clear(&wait_set_) != RCL_RET_OK) {
|
||||
throw std::runtime_error("Couldn't clear wait set");
|
||||
}
|
||||
}
|
||||
}
|
||||
// clear wait set
|
||||
if (rcl_wait_set_clear(&wait_set_) != RCL_RET_OK) {
|
||||
throw std::runtime_error("Couldn't clear wait set");
|
||||
}
|
||||
|
||||
// The size of waitables are accounted for in size of the other entities
|
||||
rcl_ret_t ret = rcl_wait_set_resize(
|
||||
&wait_set_, memory_strategy_->number_of_ready_subscriptions(),
|
||||
memory_strategy_->number_of_guard_conditions(), memory_strategy_->number_of_ready_timers(),
|
||||
memory_strategy_->number_of_ready_clients(), memory_strategy_->number_of_ready_services());
|
||||
if (RCL_RET_OK != ret) {
|
||||
throw std::runtime_error(
|
||||
std::string("Couldn't resize the wait set : ") + rcl_get_error_string().str);
|
||||
}
|
||||
// The size of waitables are accounted for in size of the other entities
|
||||
rcl_ret_t ret = rcl_wait_set_resize(
|
||||
&wait_set_, memory_strategy_->number_of_ready_subscriptions(),
|
||||
memory_strategy_->number_of_guard_conditions(), memory_strategy_->number_of_ready_timers(),
|
||||
memory_strategy_->number_of_ready_clients(), memory_strategy_->number_of_ready_services(),
|
||||
memory_strategy_->number_of_ready_events());
|
||||
if (RCL_RET_OK != ret) {
|
||||
throw std::runtime_error(
|
||||
std::string("Couldn't resize the wait set : ") + rcl_get_error_string().str);
|
||||
}
|
||||
|
||||
if (!memory_strategy_->add_handles_to_wait_set(&wait_set_)) {
|
||||
throw std::runtime_error("Couldn't fill wait set");
|
||||
if (!memory_strategy_->add_handles_to_wait_set(&wait_set_)) {
|
||||
throw std::runtime_error("Couldn't fill wait set");
|
||||
}
|
||||
}
|
||||
rcl_ret_t status =
|
||||
rcl_wait(&wait_set_, std::chrono::duration_cast<std::chrono::nanoseconds>(timeout).count());
|
||||
|
||||
@@ -83,6 +83,11 @@ MultiThreadedExecutor::run(size_t)
|
||||
if (any_exec.timer) {
|
||||
// Guard against multiple threads getting the same timer.
|
||||
if (scheduled_timers_.count(any_exec.timer) != 0) {
|
||||
// Make sure that any_exec's callback group is reset before
|
||||
// the lock is released.
|
||||
if (any_exec.callback_group) {
|
||||
any_exec.callback_group->can_be_taken_from().store(true);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
scheduled_timers_.insert(any_exec.timer);
|
||||
|
||||
@@ -79,6 +79,7 @@ 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) {
|
||||
@@ -145,7 +146,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);
|
||||
ret = rcl_wait_set_resize(&wait_set_, 0, node_graph_interfaces_size + 2, 0, 0, 0, 0);
|
||||
if (RCL_RET_OK != ret) {
|
||||
throw_from_rcl_error(ret, "failed to resize wait set");
|
||||
}
|
||||
|
||||
@@ -29,6 +29,21 @@ 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)
|
||||
|
||||
@@ -20,7 +20,7 @@ using rclcpp::memory_strategy::MemoryStrategy;
|
||||
rclcpp::SubscriptionBase::SharedPtr
|
||||
MemoryStrategy::get_subscription_by_handle(
|
||||
std::shared_ptr<const rcl_subscription_t> subscriber_handle,
|
||||
const WeakNodeVector & weak_nodes)
|
||||
const WeakNodeList & weak_nodes)
|
||||
{
|
||||
for (auto & weak_node : weak_nodes) {
|
||||
auto node = weak_node.lock();
|
||||
@@ -51,7 +51,7 @@ MemoryStrategy::get_subscription_by_handle(
|
||||
rclcpp::ServiceBase::SharedPtr
|
||||
MemoryStrategy::get_service_by_handle(
|
||||
std::shared_ptr<const rcl_service_t> service_handle,
|
||||
const WeakNodeVector & weak_nodes)
|
||||
const WeakNodeList & weak_nodes)
|
||||
{
|
||||
for (auto & weak_node : weak_nodes) {
|
||||
auto node = weak_node.lock();
|
||||
@@ -77,7 +77,7 @@ MemoryStrategy::get_service_by_handle(
|
||||
rclcpp::ClientBase::SharedPtr
|
||||
MemoryStrategy::get_client_by_handle(
|
||||
std::shared_ptr<const rcl_client_t> client_handle,
|
||||
const WeakNodeVector & weak_nodes)
|
||||
const WeakNodeList & weak_nodes)
|
||||
{
|
||||
for (auto & weak_node : weak_nodes) {
|
||||
auto node = weak_node.lock();
|
||||
@@ -103,7 +103,7 @@ MemoryStrategy::get_client_by_handle(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
|
||||
MemoryStrategy::get_node_by_group(
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group,
|
||||
const WeakNodeVector & weak_nodes)
|
||||
const WeakNodeList & weak_nodes)
|
||||
{
|
||||
if (!group) {
|
||||
return nullptr;
|
||||
@@ -126,7 +126,7 @@ MemoryStrategy::get_node_by_group(
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
MemoryStrategy::get_group_by_subscription(
|
||||
rclcpp::SubscriptionBase::SharedPtr subscription,
|
||||
const WeakNodeVector & weak_nodes)
|
||||
const WeakNodeList & weak_nodes)
|
||||
{
|
||||
for (auto & weak_node : weak_nodes) {
|
||||
auto node = weak_node.lock();
|
||||
@@ -152,7 +152,7 @@ MemoryStrategy::get_group_by_subscription(
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
MemoryStrategy::get_group_by_service(
|
||||
rclcpp::ServiceBase::SharedPtr service,
|
||||
const WeakNodeVector & weak_nodes)
|
||||
const WeakNodeList & weak_nodes)
|
||||
{
|
||||
for (auto & weak_node : weak_nodes) {
|
||||
auto node = weak_node.lock();
|
||||
@@ -178,7 +178,7 @@ MemoryStrategy::get_group_by_service(
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
MemoryStrategy::get_group_by_client(
|
||||
rclcpp::ClientBase::SharedPtr client,
|
||||
const WeakNodeVector & weak_nodes)
|
||||
const WeakNodeList & weak_nodes)
|
||||
{
|
||||
for (auto & weak_node : weak_nodes) {
|
||||
auto node = weak_node.lock();
|
||||
@@ -204,7 +204,7 @@ MemoryStrategy::get_group_by_client(
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
MemoryStrategy::get_group_by_waitable(
|
||||
rclcpp::Waitable::SharedPtr waitable,
|
||||
const WeakNodeVector & weak_nodes)
|
||||
const WeakNodeList & weak_nodes)
|
||||
{
|
||||
for (auto & weak_node : weak_nodes) {
|
||||
auto node = weak_node.lock();
|
||||
|
||||
@@ -109,7 +109,11 @@ Node::Node(
|
||||
const std::string & namespace_,
|
||||
const NodeOptions & options)
|
||||
: node_base_(new rclcpp::node_interfaces::NodeBase(
|
||||
node_name, namespace_, options)),
|
||||
node_name,
|
||||
namespace_,
|
||||
options.context(),
|
||||
*(options.get_rcl_node_options()),
|
||||
options.use_intra_process_comms())),
|
||||
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,13 +132,13 @@ Node::Node(
|
||||
node_topics_,
|
||||
node_services_,
|
||||
node_clock_,
|
||||
options.initial_parameters(),
|
||||
options.use_intra_process_comms(),
|
||||
options.parameter_overrides(),
|
||||
options.start_parameter_services(),
|
||||
options.start_parameter_event_publisher(),
|
||||
options.parameter_event_qos_profile(),
|
||||
options.parameter_event_qos(),
|
||||
options.parameter_event_publisher_options(),
|
||||
options.allow_undeclared_parameters(),
|
||||
options.automatically_declare_initial_parameters()
|
||||
options.automatically_declare_parameters_from_overrides()
|
||||
)),
|
||||
node_time_source_(new rclcpp::node_interfaces::NodeTimeSource(
|
||||
node_base_,
|
||||
@@ -470,3 +474,9 @@ Node::get_node_options() const
|
||||
{
|
||||
return this->node_options_;
|
||||
}
|
||||
|
||||
bool
|
||||
Node::assert_liveliness() const
|
||||
{
|
||||
return node_base_->assert_liveliness();
|
||||
}
|
||||
|
||||
@@ -32,8 +32,11 @@ using rclcpp::node_interfaces::NodeBase;
|
||||
NodeBase::NodeBase(
|
||||
const std::string & node_name,
|
||||
const std::string & namespace_,
|
||||
const rclcpp::NodeOptions & options)
|
||||
: context_(options.context()),
|
||||
rclcpp::Context::SharedPtr context,
|
||||
const rcl_node_options_t & rcl_node_options,
|
||||
bool use_intra_process_default)
|
||||
: context_(context),
|
||||
use_intra_process_default_(use_intra_process_default),
|
||||
node_handle_(nullptr),
|
||||
default_callback_group_(nullptr),
|
||||
associated_with_executor_(false),
|
||||
@@ -42,7 +45,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(
|
||||
¬ify_guard_condition_, options.context()->get_rcl_context().get(), guard_condition_options);
|
||||
¬ify_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");
|
||||
}
|
||||
@@ -63,7 +66,7 @@ NodeBase::NodeBase(
|
||||
ret = rcl_node_init(
|
||||
rcl_node.get(),
|
||||
node_name.c_str(), namespace_.c_str(),
|
||||
options.context()->get_rcl_context().get(), options.get_rcl_node_options());
|
||||
context_->get_rcl_context().get(), &rcl_node_options);
|
||||
if (ret != RCL_RET_OK) {
|
||||
// Finalize the interrupt guard condition.
|
||||
finalize_notify_guard_condition();
|
||||
@@ -197,6 +200,12 @@ 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)
|
||||
{
|
||||
@@ -253,3 +262,9 @@ 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_;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "rclcpp/node_interfaces/node_graph.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -136,9 +137,24 @@ NodeGraph::get_node_names() const
|
||||
std::vector<std::string> nodes;
|
||||
auto names_and_namespaces = get_node_names_and_namespaces();
|
||||
|
||||
for (const auto & it : names_and_namespaces) {
|
||||
nodes.push_back(it.first);
|
||||
}
|
||||
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;
|
||||
}
|
||||
);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
@@ -173,10 +189,12 @@ 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_c.size);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> node_names;
|
||||
node_names.reserve(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.push_back(std::make_pair(node_names_c.data[i], node_namespaces_c.data[i]));
|
||||
node_names.emplace_back(node_names_c.data[i], node_namespaces_c.data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,9 +320,11 @@ rclcpp::Event::SharedPtr
|
||||
NodeGraph::get_graph_event()
|
||||
{
|
||||
auto event = rclcpp::Event::make_shared();
|
||||
std::lock_guard<std::mutex> graph_changed_lock(graph_mutex_);
|
||||
graph_events_.push_back(event);
|
||||
graph_users_count_++;
|
||||
{
|
||||
std::lock_guard<std::mutex> graph_changed_lock(graph_mutex_);
|
||||
graph_events_.push_back(event);
|
||||
graph_users_count_++;
|
||||
}
|
||||
// on first call, add node to graph_listener_
|
||||
if (should_add_to_graph_listener_.exchange(false)) {
|
||||
graph_listener_->add_node(this);
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
|
||||
#include <rcl_yaml_param_parser/parser.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
@@ -45,16 +48,16 @@ using rclcpp::node_interfaces::NodeParameters;
|
||||
NodeParameters::NodeParameters(
|
||||
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
|
||||
const rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
|
||||
const rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
|
||||
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,
|
||||
const std::vector<rclcpp::Parameter> & parameter_overrides,
|
||||
bool start_parameter_services,
|
||||
bool start_parameter_event_publisher,
|
||||
const rmw_qos_profile_t & parameter_event_qos_profile,
|
||||
const rclcpp::QoS & parameter_event_qos,
|
||||
const rclcpp::PublisherOptionsBase & parameter_event_publisher_options,
|
||||
bool allow_undeclared_parameters,
|
||||
bool automatically_declare_initial_parameters)
|
||||
bool automatically_declare_parameters_from_overrides)
|
||||
: allow_undeclared_(allow_undeclared_parameters),
|
||||
events_publisher_(nullptr),
|
||||
node_logging_(node_logging),
|
||||
@@ -64,7 +67,9 @@ NodeParameters::NodeParameters(
|
||||
using PublisherT = rclcpp::Publisher<MessageT>;
|
||||
using AllocatorT = std::allocator<void>;
|
||||
// TODO(wjwwood): expose this allocator through the Parameter interface.
|
||||
auto allocator = std::make_shared<AllocatorT>();
|
||||
rclcpp::PublisherOptionsWithAllocator<AllocatorT> publisher_options(
|
||||
parameter_event_publisher_options);
|
||||
publisher_options.allocator = std::make_shared<AllocatorT>();
|
||||
|
||||
if (start_parameter_services) {
|
||||
parameter_service_ = std::make_shared<ParameterService>(node_base, node_services, this);
|
||||
@@ -72,11 +77,10 @@ NodeParameters::NodeParameters(
|
||||
|
||||
if (start_parameter_event_publisher) {
|
||||
events_publisher_ = rclcpp::create_publisher<MessageT, AllocatorT, PublisherT>(
|
||||
node_topics.get(),
|
||||
node_topics,
|
||||
"parameter_events",
|
||||
parameter_event_qos_profile,
|
||||
use_intra_process,
|
||||
allocator);
|
||||
parameter_event_qos,
|
||||
publisher_options);
|
||||
}
|
||||
|
||||
// Get the node options
|
||||
@@ -121,18 +125,7 @@ NodeParameters::NodeParameters(
|
||||
get_yaml_paths(&(options->arguments));
|
||||
|
||||
// Get fully qualified node name post-remapping to use to find node's params in yaml files
|
||||
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;
|
||||
}
|
||||
combined_name_ = node_base->get_fully_qualified_name();
|
||||
|
||||
// TODO(sloretz) use rcl to parse yaml when circular dependency is solved
|
||||
// See https://github.com/ros2/rcl/issues/252
|
||||
@@ -151,28 +144,29 @@ NodeParameters::NodeParameters(
|
||||
|
||||
rclcpp::ParameterMap initial_map = rclcpp::parameter_map_from(yaml_params);
|
||||
rcl_yaml_node_struct_fini(yaml_params);
|
||||
auto iter = initial_map.find(combined_name_);
|
||||
if (initial_map.end() == iter) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Combine parameter yaml files, overwriting values in older ones
|
||||
for (auto & param : iter->second) {
|
||||
initial_parameter_values_[param.get_name()] =
|
||||
rclcpp::ParameterValue(param.get_value_message());
|
||||
for (auto iter = initial_map.begin(); initial_map.end() != iter; iter++) {
|
||||
// TODO(cottsay) implement further wildcard matching
|
||||
if (iter->first == "/**" || iter->first == combined_name_) {
|
||||
// Combine parameter yaml files, overwriting values in older ones
|
||||
for (auto & param : iter->second) {
|
||||
parameter_overrides_[param.get_name()] =
|
||||
rclcpp::ParameterValue(param.get_value_message());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// initial values passed to constructor overwrite yaml file sources
|
||||
for (auto & param : initial_parameters) {
|
||||
initial_parameter_values_[param.get_name()] =
|
||||
// parameter overrides passed to constructor will overwrite overrides from yaml file sources
|
||||
for (auto & param : parameter_overrides) {
|
||||
parameter_overrides_[param.get_name()] =
|
||||
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 (automatically_declare_parameters_from_overrides) {
|
||||
for (const auto & pair : this->get_parameter_overrides()) {
|
||||
if (!this->has_parameter(pair.first)) {
|
||||
this->declare_parameter(
|
||||
pair.first,
|
||||
@@ -195,6 +189,103 @@ __lockless_has_parameter(
|
||||
return parameters.find(name) != parameters.end();
|
||||
}
|
||||
|
||||
// see https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon
|
||||
RCLCPP_LOCAL
|
||||
bool
|
||||
__are_doubles_equal(double x, double y, double ulp = 100.0)
|
||||
{
|
||||
return std::abs(x - y) <= std::numeric_limits<double>::epsilon() * std::abs(x + y) * ulp;
|
||||
}
|
||||
|
||||
RCLCPP_LOCAL
|
||||
inline
|
||||
void
|
||||
format_reason(std::string & reason, const std::string & name, const char * range_type)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "Parameter {" << name << "} doesn't comply with " << range_type << " range.";
|
||||
reason = ss.str();
|
||||
}
|
||||
|
||||
RCLCPP_LOCAL
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
__check_parameter_value_in_range(
|
||||
const rcl_interfaces::msg::ParameterDescriptor & descriptor,
|
||||
const rclcpp::ParameterValue & value)
|
||||
{
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
result.successful = true;
|
||||
if (!descriptor.integer_range.empty() && value.get_type() == rclcpp::PARAMETER_INTEGER) {
|
||||
int64_t v = value.get<int64_t>();
|
||||
auto integer_range = descriptor.integer_range.at(0);
|
||||
if (v == integer_range.from_value || v == integer_range.to_value) {
|
||||
return result;
|
||||
}
|
||||
if ((v < integer_range.from_value) || (v > integer_range.to_value)) {
|
||||
result.successful = false;
|
||||
format_reason(result.reason, descriptor.name, "integer");
|
||||
return result;
|
||||
}
|
||||
if (integer_range.step == 0) {
|
||||
return result;
|
||||
}
|
||||
if (((v - integer_range.from_value) % integer_range.step) == 0) {
|
||||
return result;
|
||||
}
|
||||
result.successful = false;
|
||||
format_reason(result.reason, descriptor.name, "integer");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!descriptor.floating_point_range.empty() && value.get_type() == rclcpp::PARAMETER_DOUBLE) {
|
||||
double v = value.get<double>();
|
||||
auto fp_range = descriptor.floating_point_range.at(0);
|
||||
if (__are_doubles_equal(v, fp_range.from_value) ||
|
||||
__are_doubles_equal(v, fp_range.to_value))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if ((v < fp_range.from_value) || (v > fp_range.to_value)) {
|
||||
result.successful = false;
|
||||
format_reason(result.reason, descriptor.name, "floating point");
|
||||
return result;
|
||||
}
|
||||
if (fp_range.step == 0.0) {
|
||||
return result;
|
||||
}
|
||||
double rounded_div = std::round((v - fp_range.from_value) / fp_range.step);
|
||||
if (__are_doubles_equal(v, fp_range.from_value + rounded_div * fp_range.step)) {
|
||||
return result;
|
||||
}
|
||||
result.successful = false;
|
||||
format_reason(result.reason, descriptor.name, "floating point");
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Return true if parameter values comply with the descriptors in parameter_infos.
|
||||
RCLCPP_LOCAL
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
__check_parameters(
|
||||
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameter_infos,
|
||||
const std::vector<rclcpp::Parameter> & parameters)
|
||||
{
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
result.successful = true;
|
||||
for (const rclcpp::Parameter & parameter : parameters) {
|
||||
const rcl_interfaces::msg::ParameterDescriptor & descriptor =
|
||||
parameter_infos[parameter.get_name()].descriptor;
|
||||
result = __check_parameter_value_in_range(
|
||||
descriptor,
|
||||
parameter.get_parameter_value());
|
||||
if (!result.successful) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
using OnParametersSetCallbackType =
|
||||
rclcpp::node_interfaces::NodeParametersInterface::OnParametersSetCallbackType;
|
||||
|
||||
@@ -211,7 +302,14 @@ __set_parameters_atomically_common(
|
||||
if (on_set_parameters_callback) {
|
||||
result = on_set_parameters_callback(parameters);
|
||||
}
|
||||
|
||||
if (!result.successful) {
|
||||
return result;
|
||||
}
|
||||
// Check if the value being set complies with the descriptor.
|
||||
result = __check_parameters(parameter_infos, parameters);
|
||||
if (!result.successful) {
|
||||
return result;
|
||||
}
|
||||
// If accepted, actually set the values.
|
||||
if (result.successful) {
|
||||
for (size_t i = 0; i < parameters.size(); ++i) {
|
||||
@@ -233,19 +331,20 @@ __declare_parameter_common(
|
||||
const rclcpp::ParameterValue & default_value,
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
|
||||
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameters_out,
|
||||
const std::map<std::string, rclcpp::ParameterValue> & initial_values,
|
||||
const std::map<std::string, rclcpp::ParameterValue> & overrides,
|
||||
OnParametersSetCallbackType on_set_parameters_callback,
|
||||
rcl_interfaces::msg::ParameterEvent * parameter_event_out)
|
||||
rcl_interfaces::msg::ParameterEvent * parameter_event_out,
|
||||
bool use_overrides = true)
|
||||
{
|
||||
using rclcpp::node_interfaces::ParameterInfo;
|
||||
std::map<std::string, ParameterInfo> parameter_infos {{name, ParameterInfo()}};
|
||||
parameter_infos.at(name).descriptor = parameter_descriptor;
|
||||
|
||||
// Use the value from the initial_values if available, otherwise use the default.
|
||||
// Use the value from the overrides if available, otherwise use the default.
|
||||
const rclcpp::ParameterValue * initial_value = &default_value;
|
||||
auto initial_value_it = initial_values.find(name);
|
||||
if (initial_value_it != initial_values.end()) {
|
||||
initial_value = &initial_value_it->second;
|
||||
auto overrides_it = overrides.find(name);
|
||||
if (use_overrides && overrides_it != overrides.end()) {
|
||||
initial_value = &overrides_it->second;
|
||||
}
|
||||
|
||||
// Check with the user's callback to see if the initial value can be set.
|
||||
@@ -292,7 +391,7 @@ NodeParameters::declare_parameter(
|
||||
default_value,
|
||||
parameter_descriptor,
|
||||
parameters_,
|
||||
initial_parameter_values_,
|
||||
parameter_overrides_,
|
||||
on_parameters_set_callback_,
|
||||
¶meter_event);
|
||||
|
||||
@@ -302,8 +401,10 @@ NodeParameters::declare_parameter(
|
||||
"parameter '" + name + "' could not be set: " + result.reason);
|
||||
}
|
||||
|
||||
// Publish the event.
|
||||
events_publisher_->publish(parameter_event);
|
||||
// Publish if events_publisher_ is not nullptr, which may be if disabled in the constructor.
|
||||
if (nullptr != events_publisher_) {
|
||||
events_publisher_->publish(parameter_event);
|
||||
}
|
||||
|
||||
return parameters_.at(name).value;
|
||||
}
|
||||
@@ -421,9 +522,10 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
|
||||
parameter_to_be_declared->get_parameter_value(),
|
||||
rcl_interfaces::msg::ParameterDescriptor(), // Implicit declare uses default descriptor.
|
||||
staged_parameter_changes,
|
||||
initial_parameter_values_,
|
||||
parameter_overrides_,
|
||||
nullptr, // callback is explicitly null, so that it is called only once, when setting below.
|
||||
¶meter_event_msg);
|
||||
¶meter_event_msg,
|
||||
false);
|
||||
if (!result.successful) {
|
||||
// Declare failed, return knowing that nothing was changed because the
|
||||
// staged changes were not applied.
|
||||
@@ -501,10 +603,10 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
|
||||
// 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);
|
||||
// Update the parameter event message and remove it.
|
||||
parameter_event_msg.deleted_parameters.push_back(
|
||||
rclcpp::Parameter(it->first, it->second.value).to_parameter_msg());
|
||||
parameters_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -741,7 +843,7 @@ NodeParameters::register_param_change_callback(ParametersCallbackFunction callba
|
||||
#endif
|
||||
|
||||
const std::map<std::string, rclcpp::ParameterValue> &
|
||||
NodeParameters::get_initial_parameter_values() const
|
||||
NodeParameters::get_parameter_overrides() const
|
||||
{
|
||||
return initial_parameter_values_;
|
||||
return parameter_overrides_;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ rclcpp::PublisherBase::SharedPtr
|
||||
NodeTopics::create_publisher(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::PublisherFactory & publisher_factory,
|
||||
rcl_publisher_options_t & publisher_options,
|
||||
const rcl_publisher_options_t & publisher_options,
|
||||
bool use_intra_process)
|
||||
{
|
||||
// Create the MessageT specific Publisher using the factory, but store it as PublisherBase.
|
||||
@@ -47,13 +47,17 @@ 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 =
|
||||
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);
|
||||
if (publisher_options.qos.history == RMW_QOS_POLICY_HISTORY_KEEP_ALL) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication is not allowed with keep all history qos policy");
|
||||
}
|
||||
if (publisher_options.qos.depth == 0) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication is not allowed with a zero qos history depth value");
|
||||
}
|
||||
uint64_t intra_process_publisher_id = ipm->add_publisher(publisher);
|
||||
publisher->setup_intra_process(
|
||||
intra_process_publisher_id,
|
||||
shared_publish_callback,
|
||||
ipm,
|
||||
publisher_options);
|
||||
}
|
||||
@@ -64,11 +68,22 @@ NodeTopics::create_publisher(
|
||||
|
||||
void
|
||||
NodeTopics::add_publisher(
|
||||
rclcpp::PublisherBase::SharedPtr publisher)
|
||||
rclcpp::PublisherBase::SharedPtr publisher,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group)
|
||||
{
|
||||
// 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;
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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();
|
||||
@@ -84,7 +99,7 @@ rclcpp::SubscriptionBase::SharedPtr
|
||||
NodeTopics::create_subscription(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::SubscriptionFactory & subscription_factory,
|
||||
rcl_subscription_options_t & subscription_options,
|
||||
const rcl_subscription_options_t & subscription_options,
|
||||
bool use_intra_process)
|
||||
{
|
||||
auto subscription = subscription_factory.create_typed_subscription(
|
||||
@@ -93,10 +108,12 @@ NodeTopics::create_subscription(
|
||||
// Setup intra process publishing if requested.
|
||||
if (use_intra_process) {
|
||||
auto context = node_base_->get_context();
|
||||
auto intra_process_manager =
|
||||
auto ipm =
|
||||
context->get_sub_context<rclcpp::intra_process_manager::IntraProcessManager>();
|
||||
subscription_factory.setup_intra_process(
|
||||
intra_process_manager, subscription, subscription_options);
|
||||
uint64_t intra_process_subscription_id = ipm->add_subscription(subscription);
|
||||
auto options_copy = subscription_options;
|
||||
options_copy.ignore_local_publications = false;
|
||||
subscription->setup_intra_process(intra_process_subscription_id, ipm, options_copy);
|
||||
}
|
||||
|
||||
// Return the completed subscription.
|
||||
@@ -114,9 +131,13 @@ 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 {
|
||||
node_base_->get_default_callback_group()->add_subscription(subscription);
|
||||
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);
|
||||
}
|
||||
|
||||
// Notify the executor that a new subscription was created using the parent Node.
|
||||
@@ -130,3 +151,9 @@ NodeTopics::add_subscription(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
NodeTopics::get_node_base_interface() const
|
||||
{
|
||||
return node_base_;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
#include "rclcpp/publisher_options.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
|
||||
using rclcpp::exceptions::throw_from_rcl_error;
|
||||
|
||||
@@ -42,6 +44,9 @@ rcl_node_options_t_destructor(rcl_node_options_t * node_options)
|
||||
"failed to finalize rcl node options: %s", rcl_get_error_string().str);
|
||||
rcl_reset_error();
|
||||
}
|
||||
|
||||
delete node_options;
|
||||
node_options = nullptr;
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
@@ -60,12 +65,19 @@ NodeOptions &
|
||||
NodeOptions::operator=(const NodeOptions & other)
|
||||
{
|
||||
if (this != &other) {
|
||||
this->node_options_.reset();
|
||||
this->context_ = other.context_;
|
||||
this->arguments_ = other.arguments_;
|
||||
this->initial_parameters_ = other.initial_parameters_;
|
||||
this->parameter_overrides_ = other.parameter_overrides_;
|
||||
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->start_parameter_event_publisher_ = other.start_parameter_event_publisher_;
|
||||
this->parameter_event_qos_ = other.parameter_event_qos_;
|
||||
this->parameter_event_publisher_options_ = other.parameter_event_publisher_options_;
|
||||
this->allow_undeclared_parameters_ = other.allow_undeclared_parameters_;
|
||||
this->automatically_declare_parameters_from_overrides_ =
|
||||
other.automatically_declare_parameters_from_overrides_;
|
||||
this->allocator_ = other.allocator_;
|
||||
}
|
||||
return *this;
|
||||
@@ -90,7 +102,7 @@ NodeOptions::get_rcl_node_options() const
|
||||
}
|
||||
}
|
||||
|
||||
if (this->arguments_.size() > std::numeric_limits<int>::max()) {
|
||||
if (this->arguments_.size() > static_cast<size_t>(std::numeric_limits<int>::max())) {
|
||||
throw_from_rcl_error(RCL_RET_INVALID_ARGUMENT, "Too many args");
|
||||
}
|
||||
|
||||
@@ -134,28 +146,28 @@ NodeOptions::arguments(const std::vector<std::string> & arguments)
|
||||
}
|
||||
|
||||
std::vector<rclcpp::Parameter> &
|
||||
NodeOptions::initial_parameters()
|
||||
NodeOptions::parameter_overrides()
|
||||
{
|
||||
return this->initial_parameters_;
|
||||
return this->parameter_overrides_;
|
||||
}
|
||||
|
||||
const std::vector<rclcpp::Parameter> &
|
||||
NodeOptions::initial_parameters() const
|
||||
NodeOptions::parameter_overrides() const
|
||||
{
|
||||
return this->initial_parameters_;
|
||||
return this->parameter_overrides_;
|
||||
}
|
||||
|
||||
NodeOptions &
|
||||
NodeOptions::initial_parameters(const std::vector<rclcpp::Parameter> & initial_parameters)
|
||||
NodeOptions::parameter_overrides(const std::vector<rclcpp::Parameter> & parameter_overrides)
|
||||
{
|
||||
this->initial_parameters_ = initial_parameters;
|
||||
this->parameter_overrides_ = parameter_overrides;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
NodeOptions::use_global_arguments() const
|
||||
{
|
||||
return this->node_options_->use_global_arguments;
|
||||
return this->use_global_arguments_;
|
||||
}
|
||||
|
||||
NodeOptions &
|
||||
@@ -205,16 +217,30 @@ NodeOptions::start_parameter_event_publisher(bool start_parameter_event_publishe
|
||||
return *this;
|
||||
}
|
||||
|
||||
const rmw_qos_profile_t &
|
||||
NodeOptions::parameter_event_qos_profile() const
|
||||
const rclcpp::QoS &
|
||||
NodeOptions::parameter_event_qos() const
|
||||
{
|
||||
return this->parameter_event_qos_profile_;
|
||||
return this->parameter_event_qos_;
|
||||
}
|
||||
|
||||
NodeOptions &
|
||||
NodeOptions::parameter_event_qos_profile(const rmw_qos_profile_t & parameter_event_qos_profile)
|
||||
NodeOptions::parameter_event_qos(const rclcpp::QoS & parameter_event_qos)
|
||||
{
|
||||
this->parameter_event_qos_profile_ = parameter_event_qos_profile;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -232,16 +258,17 @@ NodeOptions::allow_undeclared_parameters(bool allow_undeclared_parameters)
|
||||
}
|
||||
|
||||
bool
|
||||
NodeOptions::automatically_declare_initial_parameters() const
|
||||
NodeOptions::automatically_declare_parameters_from_overrides() const
|
||||
{
|
||||
return this->automatically_declare_initial_parameters_;
|
||||
return this->automatically_declare_parameters_from_overrides_;
|
||||
}
|
||||
|
||||
NodeOptions &
|
||||
NodeOptions::automatically_declare_initial_parameters(
|
||||
bool automatically_declare_initial_parameters)
|
||||
NodeOptions::automatically_declare_parameters_from_overrides(
|
||||
bool automatically_declare_parameters_from_overrides)
|
||||
{
|
||||
this->automatically_declare_initial_parameters_ = automatically_declare_initial_parameters;
|
||||
this->automatically_declare_parameters_from_overrides_ =
|
||||
automatically_declare_parameters_from_overrides;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -275,7 +302,7 @@ NodeOptions::get_domain_id_from_env() const
|
||||
_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);
|
||||
uint32_t number = static_cast<uint32_t>(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
|
||||
|
||||
@@ -146,7 +146,7 @@ AsyncParametersClient::get_parameters(
|
||||
auto & pvalues = cb_f.get()->values;
|
||||
|
||||
for (auto & pvalue : pvalues) {
|
||||
auto i = &pvalue - &pvalues[0];
|
||||
auto i = static_cast<size_t>(&pvalue - &pvalues[0]);
|
||||
rcl_interfaces::msg::Parameter parameter;
|
||||
parameter.name = request->names[i];
|
||||
parameter.value = pvalue;
|
||||
|
||||
@@ -57,11 +57,15 @@ ParameterService::ParameterService(
|
||||
const std::shared_ptr<rcl_interfaces::srv::GetParameterTypes::Request> request,
|
||||
std::shared_ptr<rcl_interfaces::srv::GetParameterTypes::Response> response)
|
||||
{
|
||||
auto types = node_params->get_parameter_types(request->names);
|
||||
std::transform(types.cbegin(), types.cend(),
|
||||
std::back_inserter(response->types), [](const uint8_t & type) {
|
||||
return static_cast<rclcpp::ParameterType>(type);
|
||||
});
|
||||
try {
|
||||
auto types = node_params->get_parameter_types(request->names);
|
||||
std::transform(types.cbegin(), types.cend(),
|
||||
std::back_inserter(response->types), [](const uint8_t & type) {
|
||||
return static_cast<rclcpp::ParameterType>(type);
|
||||
});
|
||||
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
|
||||
RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Failed to get parameter types: %s", ex.what());
|
||||
}
|
||||
},
|
||||
qos_profile, nullptr);
|
||||
|
||||
@@ -73,12 +77,20 @@ ParameterService::ParameterService(
|
||||
const std::shared_ptr<rcl_interfaces::srv::SetParameters::Request> request,
|
||||
std::shared_ptr<rcl_interfaces::srv::SetParameters::Response> response)
|
||||
{
|
||||
std::vector<rclcpp::Parameter> pvariants;
|
||||
// Set parameters one-by-one, since there's no way to return a partial result if
|
||||
// set_parameters() fails.
|
||||
auto result = rcl_interfaces::msg::SetParametersResult();
|
||||
for (auto & p : request->parameters) {
|
||||
pvariants.push_back(rclcpp::Parameter::from_parameter_msg(p));
|
||||
try {
|
||||
result = node_params->set_parameters_atomically(
|
||||
{rclcpp::Parameter::from_parameter_msg(p)});
|
||||
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
|
||||
RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Failed to set parameter: %s", ex.what());
|
||||
result.successful = false;
|
||||
result.reason = ex.what();
|
||||
}
|
||||
response->results.push_back(result);
|
||||
}
|
||||
auto results = node_params->set_parameters(pvariants);
|
||||
response->results = results;
|
||||
},
|
||||
qos_profile, nullptr);
|
||||
|
||||
@@ -96,8 +108,15 @@ ParameterService::ParameterService(
|
||||
[](const rcl_interfaces::msg::Parameter & p) {
|
||||
return rclcpp::Parameter::from_parameter_msg(p);
|
||||
});
|
||||
auto result = node_params->set_parameters_atomically(pvariants);
|
||||
response->result = result;
|
||||
try {
|
||||
auto result = node_params->set_parameters_atomically(pvariants);
|
||||
response->result = result;
|
||||
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
|
||||
RCLCPP_WARN(
|
||||
rclcpp::get_logger("rclcpp"), "Failed to set parameters atomically: %s", ex.what());
|
||||
response->result.successful = false;
|
||||
response->result.reason = "One or more parameters wer not declared before setting";
|
||||
}
|
||||
},
|
||||
qos_profile, nullptr);
|
||||
|
||||
@@ -109,8 +128,12 @@ ParameterService::ParameterService(
|
||||
const std::shared_ptr<rcl_interfaces::srv::DescribeParameters::Request> request,
|
||||
std::shared_ptr<rcl_interfaces::srv::DescribeParameters::Response> response)
|
||||
{
|
||||
auto descriptors = node_params->describe_parameters(request->names);
|
||||
response->descriptors = descriptors;
|
||||
try {
|
||||
auto descriptors = node_params->describe_parameters(request->names);
|
||||
response->descriptors = descriptors;
|
||||
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
|
||||
RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Failed to describe parameters: %s", ex.what());
|
||||
}
|
||||
},
|
||||
qos_profile, nullptr);
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ ParameterValue::ParameterValue(const int64_t int_value)
|
||||
|
||||
ParameterValue::ParameterValue(const float double_value)
|
||||
{
|
||||
value_.double_value = double_value;
|
||||
value_.double_value = static_cast<double>(double_value);
|
||||
value_.type = rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "rclcpp/publisher.hpp"
|
||||
#include "rclcpp/publisher_base.hpp"
|
||||
|
||||
#include <rmw/error_handling.h>
|
||||
#include <rmw/rmw.h>
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl_interfaces/msg/intra_process_message.hpp"
|
||||
#include "rcutils/logging_macros.h"
|
||||
@@ -30,10 +31,10 @@
|
||||
#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;
|
||||
|
||||
@@ -43,8 +44,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),
|
||||
store_intra_process_message_(nullptr)
|
||||
intra_process_is_enabled_(false), intra_process_publisher_id_(0)
|
||||
{
|
||||
rcl_ret_t ret = rcl_publisher_init(
|
||||
&publisher_handle_,
|
||||
@@ -81,6 +81,9 @@ 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",
|
||||
@@ -154,6 +157,12 @@ 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
|
||||
{
|
||||
@@ -208,6 +217,12 @@ PublisherBase::get_actual_qos() const
|
||||
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
|
||||
{
|
||||
@@ -235,16 +250,22 @@ 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,
|
||||
StoreMessageCallbackT store_callback,
|
||||
IntraProcessManagerSharedPtr ipm,
|
||||
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(
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication is not allowed with durability qos policy non-volatile");
|
||||
}
|
||||
const char * topic_name = this->get_topic_name();
|
||||
@@ -275,7 +296,6 @@ PublisherBase::setup_intra_process(
|
||||
}
|
||||
|
||||
intra_process_publisher_id_ = intra_process_publisher_id;
|
||||
store_intra_process_message_ = store_callback;
|
||||
weak_ipm_ = ipm;
|
||||
intra_process_is_enabled_ = true;
|
||||
|
||||
207
rclcpp/src/rclcpp/qos.cpp
Normal file
207
rclcpp/src/rclcpp/qos.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
// 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::durability_volatile()
|
||||
{
|
||||
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
|
||||
55
rclcpp/src/rclcpp/qos_event.cpp
Normal file
55
rclcpp/src/rclcpp/qos_event.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#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
|
||||
@@ -165,13 +165,15 @@ __safe_strerror(int errnum, char * buffer, size_t buffer_length)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
strerror_s(buffer, buffer_length, errnum);
|
||||
#elif (defined(_GNU_SOURCE) && !defined(ANDROID))
|
||||
#elif defined(_GNU_SOURCE) && (!defined(ANDROID) || __ANDROID_API__ >= 23)
|
||||
/* GNU-specific */
|
||||
char * msg = strerror_r(errnum, buffer, buffer_length);
|
||||
if (msg != buffer) {
|
||||
strncpy(buffer, msg, buffer_length);
|
||||
buffer[buffer_length - 1] = '\0';
|
||||
}
|
||||
#else
|
||||
/* XSI-compliant */
|
||||
int error_status = strerror_r(errnum, buffer, buffer_length);
|
||||
if (error_status != 0) {
|
||||
throw std::runtime_error("Failed to get error string for errno: " + std::to_string(errnum));
|
||||
|
||||
@@ -12,11 +12,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "rclcpp/subscription.hpp"
|
||||
#include "rclcpp/subscription_base.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/expand_topic_or_service_name.hpp"
|
||||
@@ -121,6 +122,12 @@ 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
|
||||
{
|
||||
@@ -147,3 +154,34 @@ SubscriptionBase::get_publisher_count() const
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -62,17 +62,13 @@ Time::Time(int64_t nanoseconds, rcl_clock_type_t clock_type)
|
||||
rcl_time_.nanoseconds = nanoseconds;
|
||||
}
|
||||
|
||||
Time::Time(const Time & rhs)
|
||||
: rcl_time_(rhs.rcl_time_)
|
||||
{
|
||||
rcl_time_.nanoseconds = rhs.rcl_time_.nanoseconds;
|
||||
}
|
||||
Time::Time(const Time & rhs) = default;
|
||||
|
||||
Time::Time(
|
||||
const builtin_interfaces::msg::Time & time_msg,
|
||||
rcl_clock_type_t ros_time)
|
||||
rcl_clock_type_t clock_type)
|
||||
: rcl_time_(init_time_point(clock_type))
|
||||
{
|
||||
rcl_time_ = init_time_point(ros_time);
|
||||
if (time_msg.sec < 0) {
|
||||
throw std::runtime_error("cannot store a negative time point in rclcpp::Time");
|
||||
}
|
||||
@@ -94,31 +90,25 @@ Time::~Time()
|
||||
Time::operator builtin_interfaces::msg::Time() const
|
||||
{
|
||||
builtin_interfaces::msg::Time msg_time;
|
||||
msg_time.sec = static_cast<std::int32_t>(RCL_NS_TO_S(rcl_time_.nanoseconds));
|
||||
msg_time.nanosec = static_cast<std::uint32_t>(rcl_time_.nanoseconds % (1000 * 1000 * 1000));
|
||||
constexpr rcl_time_point_value_t kRemainder = RCL_S_TO_NS(1);
|
||||
const auto result = std::div(rcl_time_.nanoseconds, kRemainder);
|
||||
if (result.rem >= 0) {
|
||||
msg_time.sec = static_cast<std::int32_t>(result.quot);
|
||||
msg_time.nanosec = static_cast<std::uint32_t>(result.rem);
|
||||
} else {
|
||||
msg_time.sec = static_cast<std::int32_t>(result.quot - 1);
|
||||
msg_time.nanosec = static_cast<std::uint32_t>(kRemainder + result.rem);
|
||||
}
|
||||
return msg_time;
|
||||
}
|
||||
|
||||
Time &
|
||||
Time::operator=(const Time & rhs)
|
||||
{
|
||||
rcl_time_ = rhs.rcl_time_;
|
||||
return *this;
|
||||
}
|
||||
Time::operator=(const Time & rhs) = default;
|
||||
|
||||
Time &
|
||||
Time::operator=(const builtin_interfaces::msg::Time & time_msg)
|
||||
{
|
||||
if (time_msg.sec < 0) {
|
||||
throw std::runtime_error("cannot store a negative time point in rclcpp::Time");
|
||||
}
|
||||
|
||||
|
||||
rcl_clock_type_t ros_time = RCL_ROS_TIME;
|
||||
rcl_time_ = init_time_point(ros_time); // TODO(tfoote) hard coded ROS here
|
||||
|
||||
rcl_time_.nanoseconds = RCL_S_TO_NS(static_cast<int64_t>(time_msg.sec));
|
||||
rcl_time_.nanoseconds += time_msg.nanosec;
|
||||
*this = Time(time_msg);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,10 +25,11 @@
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/parameter_client.hpp"
|
||||
#include "rclcpp/parameter_events_filter.hpp"
|
||||
#include "rclcpp/time.hpp"
|
||||
#include "rclcpp/time_source.hpp"
|
||||
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
@@ -104,22 +105,16 @@ void TimeSource::attachNode(
|
||||
}
|
||||
|
||||
// TODO(tfoote) use parameters interface not subscribe to events via topic ticketed #609
|
||||
parameter_client_ = std::make_shared<rclcpp::AsyncParametersClient>(
|
||||
node_base_,
|
||||
parameter_subscription_ = rclcpp::AsyncParametersClient::on_parameter_event(
|
||||
node_topics_,
|
||||
node_graph_,
|
||||
node_services_
|
||||
);
|
||||
parameter_subscription_ =
|
||||
parameter_client_->on_parameter_event(std::bind(&TimeSource::on_parameter_event,
|
||||
this, std::placeholders::_1));
|
||||
std::bind(&TimeSource::on_parameter_event, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
void TimeSource::detachNode()
|
||||
{
|
||||
this->ros_time_active_ = false;
|
||||
clock_subscription_.reset();
|
||||
parameter_client_.reset();
|
||||
parameter_subscription_.reset();
|
||||
node_base_.reset();
|
||||
node_topics_.reset();
|
||||
node_graph_.reset();
|
||||
@@ -208,26 +203,13 @@ void TimeSource::create_clock_sub()
|
||||
// Subscription already created.
|
||||
return;
|
||||
}
|
||||
const std::string topic_name = "/clock";
|
||||
|
||||
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);
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
void TimeSource::destroy_clock_sub()
|
||||
@@ -238,13 +220,17 @@ void TimeSource::destroy_clock_sub()
|
||||
|
||||
void TimeSource::on_parameter_event(const rcl_interfaces::msg::ParameterEvent::SharedPtr event)
|
||||
{
|
||||
// Filter out events on 'use_sim_time' parameter instances in other nodes.
|
||||
if (event->node != node_base_->get_fully_qualified_name()) {
|
||||
return;
|
||||
}
|
||||
// Filter for only 'use_sim_time' being added or changed.
|
||||
rclcpp::ParameterEventsFilter filter(event, {"use_sim_time"},
|
||||
{rclcpp::ParameterEventsFilter::EventType::NEW,
|
||||
rclcpp::ParameterEventsFilter::EventType::CHANGED});
|
||||
for (auto & it : filter.get_events()) {
|
||||
if (it.second->value.type != ParameterType::PARAMETER_BOOL) {
|
||||
RCLCPP_ERROR(logger_, "use_sim_time parameter set to something besides a bool");
|
||||
RCLCPP_ERROR(logger_, "use_sim_time parameter cannot be set to anything but a bool");
|
||||
continue;
|
||||
}
|
||||
if (it.second->value.bool_value) {
|
||||
|
||||
@@ -103,9 +103,9 @@ remove_ros_arguments(int argc, char const * const argv[])
|
||||
throw exceptions::RCLError(base_exc, "");
|
||||
}
|
||||
|
||||
std::vector<std::string> return_arguments(nonros_argc);
|
||||
std::vector<std::string> return_arguments(static_cast<size_t>(nonros_argc));
|
||||
|
||||
for (int ii = 0; ii < nonros_argc; ++ii) {
|
||||
for (size_t ii = 0; ii < static_cast<size_t>(nonros_argc); ++ii) {
|
||||
return_arguments[ii] = std::string(nonros_argv[ii]);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,12 @@ 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()
|
||||
{
|
||||
|
||||
@@ -86,7 +86,7 @@ TEST_F(TestMultiThreadedExecutor, timer_over_take) {
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(last_mutex);
|
||||
double diff = std::abs((now - last).nanoseconds()) / 1.0e9;
|
||||
double diff = static_cast<double>(std::abs((now - last).nanoseconds())) / 1.0e9;
|
||||
last = now;
|
||||
|
||||
if (diff < PERIOD - TOLERANCE || diff > PERIOD + TOLERANCE) {
|
||||
|
||||
64
rclcpp/test/node_interfaces/node_wrapper.hpp
Normal file
64
rclcpp/test/node_interfaces/node_wrapper.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
// 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_
|
||||
@@ -0,0 +1,28 @@
|
||||
// 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;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// 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;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// 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;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// 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;
|
||||
}
|
||||
117
rclcpp/test/node_interfaces/test_get_node_interfaces.cpp
Normal file
117
rclcpp/test/node_interfaces/test_get_node_interfaces.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
// 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, rclcpp_node_pointer) {
|
||||
rclcpp::Node * node_pointer = this->node.get();
|
||||
auto result = rclcpp::node_interfaces::get_node_topics_interface(node_pointer);
|
||||
static_assert(
|
||||
std::is_same<
|
||||
rclcpp::node_interfaces::NodeTopicsInterface *,
|
||||
decltype(result)
|
||||
>::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *");
|
||||
}
|
||||
|
||||
TEST_F(TestGetNodeInterfaces, node_pointer) {
|
||||
NodeWrapper * wrapped_node_pointer = this->wrapped_node.get();
|
||||
auto result = rclcpp::node_interfaces::get_node_topics_interface(wrapped_node_pointer);
|
||||
static_assert(
|
||||
std::is_same<
|
||||
rclcpp::node_interfaces::NodeTopicsInterface *,
|
||||
decltype(result)
|
||||
>::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *");
|
||||
}
|
||||
|
||||
TEST_F(TestGetNodeInterfaces, interface_shared_pointer) {
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface> interface_shared_ptr =
|
||||
this->node->get_node_topics_interface();
|
||||
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 *");
|
||||
}
|
||||
57
rclcpp/test/rclcpp/test_node_options.cpp
Normal file
57
rclcpp/test/rclcpp/test_node_options.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/allocator.h"
|
||||
#include "rcl/arguments.h"
|
||||
#include "rcl/remap.h"
|
||||
|
||||
#include "rclcpp/node_options.hpp"
|
||||
|
||||
|
||||
TEST(TestNodeOptions, use_global_arguments) {
|
||||
{
|
||||
auto options = rclcpp::NodeOptions();
|
||||
EXPECT_TRUE(options.use_global_arguments());
|
||||
EXPECT_TRUE(options.get_rcl_node_options()->use_global_arguments);
|
||||
}
|
||||
|
||||
{
|
||||
auto options = rclcpp::NodeOptions().use_global_arguments(false);
|
||||
EXPECT_FALSE(options.use_global_arguments());
|
||||
EXPECT_FALSE(options.get_rcl_node_options()->use_global_arguments);
|
||||
}
|
||||
|
||||
{
|
||||
auto options = rclcpp::NodeOptions().use_global_arguments(true);
|
||||
EXPECT_TRUE(options.use_global_arguments());
|
||||
EXPECT_TRUE(options.get_rcl_node_options()->use_global_arguments);
|
||||
}
|
||||
|
||||
{
|
||||
auto options = rclcpp::NodeOptions();
|
||||
EXPECT_TRUE(options.use_global_arguments());
|
||||
EXPECT_TRUE(options.get_rcl_node_options()->use_global_arguments);
|
||||
options.use_global_arguments(false);
|
||||
EXPECT_FALSE(options.use_global_arguments());
|
||||
EXPECT_FALSE(options.get_rcl_node_options()->use_global_arguments);
|
||||
options.use_global_arguments(true);
|
||||
EXPECT_TRUE(options.use_global_arguments());
|
||||
EXPECT_TRUE(options.get_rcl_node_options()->use_global_arguments);
|
||||
}
|
||||
}
|
||||
63
rclcpp/test/test_create_timer.cpp
Normal file
63
rclcpp/test/test_create_timer.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/create_timer.hpp"
|
||||
#include "rclcpp/executors.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "node_interfaces/node_wrapper.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
TEST(TestCreateTimer, timer_executes)
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
auto node = std::make_shared<rclcpp::Node>("test_create_timer_node");
|
||||
|
||||
std::atomic<bool> got_callback{false};
|
||||
|
||||
rclcpp::TimerBase::SharedPtr timer;
|
||||
timer = rclcpp::create_timer(
|
||||
node,
|
||||
node->get_clock(),
|
||||
rclcpp::Duration(0ms),
|
||||
[&got_callback, &timer]() {
|
||||
got_callback = true;
|
||||
timer->cancel();
|
||||
});
|
||||
|
||||
rclcpp::spin_some(node);
|
||||
|
||||
ASSERT_TRUE(got_callback);
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
TEST(TestCreateTimer, call_with_node_wrapper_compiles)
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
NodeWrapper node("test_create_timer_call_with_node_wrapper_compiles");
|
||||
|
||||
rclcpp::TimerBase::SharedPtr timer;
|
||||
timer = rclcpp::create_timer(
|
||||
node,
|
||||
node.get_node_clock_interface()->get_clock(),
|
||||
rclcpp::Duration(0ms),
|
||||
[]() {});
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
@@ -32,11 +32,7 @@ class TestDuration : public ::testing::Test
|
||||
{
|
||||
};
|
||||
|
||||
// TEST(TestDuration, conversions) {
|
||||
// TODO(tfoote) Implement conversion methods
|
||||
// }
|
||||
|
||||
TEST(TestDuration, operators) {
|
||||
TEST_F(TestDuration, operators) {
|
||||
rclcpp::Duration old(1, 0);
|
||||
rclcpp::Duration young(2, 0);
|
||||
|
||||
@@ -45,28 +41,30 @@ TEST(TestDuration, operators) {
|
||||
EXPECT_TRUE(old <= young);
|
||||
EXPECT_TRUE(young >= old);
|
||||
EXPECT_FALSE(young == old);
|
||||
EXPECT_TRUE(young != old);
|
||||
|
||||
rclcpp::Duration add = old + young;
|
||||
EXPECT_EQ(add.nanoseconds(), (rcl_duration_value_t)(old.nanoseconds() + young.nanoseconds()));
|
||||
EXPECT_EQ(add.nanoseconds(), old.nanoseconds() + young.nanoseconds());
|
||||
EXPECT_EQ(add, old + young);
|
||||
|
||||
rclcpp::Duration sub = young - old;
|
||||
EXPECT_EQ(sub.nanoseconds(), (rcl_duration_value_t)(young.nanoseconds() - old.nanoseconds()));
|
||||
EXPECT_EQ(sub.nanoseconds(), young.nanoseconds() - old.nanoseconds());
|
||||
EXPECT_EQ(sub, young - old);
|
||||
|
||||
rclcpp::Duration scale = old * 3;
|
||||
EXPECT_EQ(scale.nanoseconds(), (rcl_duration_value_t)(old.nanoseconds() * 3));
|
||||
EXPECT_EQ(scale.nanoseconds(), old.nanoseconds() * 3);
|
||||
|
||||
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);
|
||||
EXPECT_TRUE(time == assignment_op_duration);
|
||||
}
|
||||
|
||||
TEST(TestDuration, chrono_overloads) {
|
||||
TEST_F(TestDuration, chrono_overloads) {
|
||||
int64_t ns = 123456789l;
|
||||
auto chrono_ns = std::chrono::nanoseconds(ns);
|
||||
auto d1 = rclcpp::Duration(ns);
|
||||
@@ -75,9 +73,17 @@ 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) {
|
||||
TEST_F(TestDuration, overflows) {
|
||||
rclcpp::Duration max(std::numeric_limits<rcl_duration_value_t>::max());
|
||||
rclcpp::Duration min(std::numeric_limits<rcl_duration_value_t>::min());
|
||||
|
||||
@@ -98,7 +104,7 @@ TEST(TestDuration, overflows) {
|
||||
EXPECT_THROW(base_d_neg * 4, std::underflow_error);
|
||||
}
|
||||
|
||||
TEST(TestDuration, negative_duration) {
|
||||
TEST_F(TestDuration, negative_duration) {
|
||||
rclcpp::Duration assignable_duration = rclcpp::Duration(0) - rclcpp::Duration(5, 0);
|
||||
|
||||
{
|
||||
@@ -121,9 +127,106 @@ TEST(TestDuration, negative_duration) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestDuration, maximum_duration) {
|
||||
TEST_F(TestDuration, maximum_duration) {
|
||||
rclcpp::Duration max_duration = rclcpp::Duration::max();
|
||||
rclcpp::Duration max(std::numeric_limits<int32_t>::max(), 999999999);
|
||||
|
||||
EXPECT_EQ(max_duration, max);
|
||||
}
|
||||
|
||||
static const int64_t HALF_SEC_IN_NS = 500 * 1000 * 1000;
|
||||
static const int64_t ONE_SEC_IN_NS = 1000 * 1000 * 1000;
|
||||
static const int64_t ONE_AND_HALF_SEC_IN_NS = 3 * HALF_SEC_IN_NS;
|
||||
|
||||
TEST_F(TestDuration, std_chrono_constructors) {
|
||||
EXPECT_EQ(rclcpp::Duration(0), rclcpp::Duration(0.0s));
|
||||
EXPECT_EQ(rclcpp::Duration(0), rclcpp::Duration(0s));
|
||||
EXPECT_EQ(rclcpp::Duration(1, HALF_SEC_IN_NS), rclcpp::Duration(1.5s));
|
||||
EXPECT_EQ(rclcpp::Duration(-1, 0), rclcpp::Duration(-1s));
|
||||
}
|
||||
|
||||
TEST_F(TestDuration, conversions) {
|
||||
{
|
||||
const rclcpp::Duration duration(HALF_SEC_IN_NS);
|
||||
const auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
|
||||
EXPECT_EQ(duration_msg.sec, 0);
|
||||
EXPECT_EQ(duration_msg.nanosec, HALF_SEC_IN_NS);
|
||||
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), HALF_SEC_IN_NS);
|
||||
|
||||
const auto rmw_time = duration.to_rmw_time();
|
||||
EXPECT_EQ(rmw_time.sec, 0u);
|
||||
EXPECT_EQ(rmw_time.nsec, static_cast<uint64_t>(HALF_SEC_IN_NS));
|
||||
|
||||
const auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
|
||||
EXPECT_EQ(chrono_duration.count(), HALF_SEC_IN_NS);
|
||||
}
|
||||
|
||||
{
|
||||
const rclcpp::Duration duration(ONE_SEC_IN_NS);
|
||||
const auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
|
||||
EXPECT_EQ(duration_msg.sec, 1);
|
||||
EXPECT_EQ(duration_msg.nanosec, 0u);
|
||||
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), ONE_SEC_IN_NS);
|
||||
|
||||
const auto rmw_time = duration.to_rmw_time();
|
||||
EXPECT_EQ(rmw_time.sec, 1u);
|
||||
EXPECT_EQ(rmw_time.nsec, 0u);
|
||||
|
||||
const auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
|
||||
EXPECT_EQ(chrono_duration.count(), ONE_SEC_IN_NS);
|
||||
}
|
||||
|
||||
{
|
||||
const rclcpp::Duration duration(ONE_AND_HALF_SEC_IN_NS);
|
||||
auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
|
||||
EXPECT_EQ(duration_msg.sec, 1);
|
||||
EXPECT_EQ(duration_msg.nanosec, HALF_SEC_IN_NS);
|
||||
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), ONE_AND_HALF_SEC_IN_NS);
|
||||
|
||||
auto rmw_time = duration.to_rmw_time();
|
||||
EXPECT_EQ(rmw_time.sec, 1u);
|
||||
EXPECT_EQ(rmw_time.nsec, static_cast<uint64_t>(HALF_SEC_IN_NS));
|
||||
|
||||
auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
|
||||
EXPECT_EQ(chrono_duration.count(), ONE_AND_HALF_SEC_IN_NS);
|
||||
}
|
||||
|
||||
{
|
||||
rclcpp::Duration duration(-HALF_SEC_IN_NS);
|
||||
auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
|
||||
EXPECT_EQ(duration_msg.sec, -1);
|
||||
EXPECT_EQ(duration_msg.nanosec, HALF_SEC_IN_NS);
|
||||
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), -HALF_SEC_IN_NS);
|
||||
|
||||
EXPECT_THROW(duration.to_rmw_time(), std::runtime_error);
|
||||
|
||||
auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
|
||||
EXPECT_EQ(chrono_duration.count(), -HALF_SEC_IN_NS);
|
||||
}
|
||||
|
||||
{
|
||||
rclcpp::Duration duration(-ONE_SEC_IN_NS);
|
||||
auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
|
||||
EXPECT_EQ(duration_msg.sec, -1);
|
||||
EXPECT_EQ(duration_msg.nanosec, 0u);
|
||||
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), -ONE_SEC_IN_NS);
|
||||
|
||||
EXPECT_THROW(duration.to_rmw_time(), std::runtime_error);
|
||||
|
||||
auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
|
||||
EXPECT_EQ(chrono_duration.count(), -ONE_SEC_IN_NS);
|
||||
}
|
||||
|
||||
{
|
||||
rclcpp::Duration duration(-ONE_AND_HALF_SEC_IN_NS);
|
||||
auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
|
||||
EXPECT_EQ(duration_msg.sec, -2);
|
||||
EXPECT_EQ(duration_msg.nanosec, HALF_SEC_IN_NS);
|
||||
EXPECT_EQ(rclcpp::Duration(duration_msg).nanoseconds(), -ONE_AND_HALF_SEC_IN_NS);
|
||||
|
||||
EXPECT_THROW(duration.to_rmw_time(), std::runtime_error);
|
||||
|
||||
auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
|
||||
EXPECT_EQ(chrono_duration.count(), -ONE_AND_HALF_SEC_IN_NS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,3 +60,10 @@ TEST_F(TestExecutors, detachOnDestruction) {
|
||||
EXPECT_NO_THROW(executor.add_node(node));
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that the executor can automatically remove expired nodes correctly
|
||||
TEST_F(TestExecutors, addTemporaryNode) {
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(std::make_shared<rclcpp::Node>("temporary_node"));
|
||||
EXPECT_NO_THROW(executor.spin_some());
|
||||
}
|
||||
|
||||
@@ -36,15 +36,15 @@ TEST_F(TestFindWeakNodes, allocator_strategy_with_weak_nodes) {
|
||||
rclcpp::memory_strategies::allocator_memory_strategy::AllocatorMemoryStrategy<>>();
|
||||
auto existing_node = rclcpp::Node::make_shared("existing_node");
|
||||
auto dead_node = rclcpp::Node::make_shared("dead_node");
|
||||
rclcpp::memory_strategy::MemoryStrategy::WeakNodeVector weak_nodes;
|
||||
rclcpp::memory_strategy::MemoryStrategy::WeakNodeList weak_nodes;
|
||||
weak_nodes.push_back(existing_node->get_node_base_interface());
|
||||
weak_nodes.push_back(dead_node->get_node_base_interface());
|
||||
|
||||
// AND
|
||||
// Delete dead_node, creating a dangling pointer in weak_nodes
|
||||
dead_node.reset();
|
||||
ASSERT_FALSE(weak_nodes[0].expired());
|
||||
ASSERT_TRUE(weak_nodes[1].expired());
|
||||
ASSERT_FALSE(weak_nodes.front().expired());
|
||||
ASSERT_TRUE(weak_nodes.back().expired());
|
||||
|
||||
// WHEN
|
||||
bool has_invalid_weak_nodes = memory_strategy->collect_entities(weak_nodes);
|
||||
@@ -64,11 +64,11 @@ TEST_F(TestFindWeakNodes, allocator_strategy_no_weak_nodes) {
|
||||
rclcpp::memory_strategies::allocator_memory_strategy::AllocatorMemoryStrategy<>>();
|
||||
auto existing_node1 = rclcpp::Node::make_shared("existing_node1");
|
||||
auto existing_node2 = rclcpp::Node::make_shared("existing_node2");
|
||||
rclcpp::memory_strategy::MemoryStrategy::WeakNodeVector weak_nodes;
|
||||
rclcpp::memory_strategy::MemoryStrategy::WeakNodeList weak_nodes;
|
||||
weak_nodes.push_back(existing_node1->get_node_base_interface());
|
||||
weak_nodes.push_back(existing_node2->get_node_base_interface());
|
||||
ASSERT_FALSE(weak_nodes[0].expired());
|
||||
ASSERT_FALSE(weak_nodes[1].expired());
|
||||
ASSERT_FALSE(weak_nodes.front().expired());
|
||||
ASSERT_FALSE(weak_nodes.back().expired());
|
||||
|
||||
// WHEN
|
||||
bool has_invalid_weak_nodes = memory_strategy->collect_entities(weak_nodes);
|
||||
|
||||
@@ -80,6 +80,12 @@ struct ObjectMember
|
||||
return 7;
|
||||
}
|
||||
|
||||
int callback_one_bool_const(bool a) const
|
||||
{
|
||||
(void)a;
|
||||
return 7;
|
||||
}
|
||||
|
||||
int callback_two_bools(bool a, bool b)
|
||||
{
|
||||
(void)a;
|
||||
@@ -394,6 +400,16 @@ TEST(TestFunctionTraits, argument_types) {
|
||||
rclcpp::function_traits::function_traits<decltype(bind_one_bool)>::template argument_type<0>
|
||||
>::value, "Functor accepts a bool as first argument");
|
||||
|
||||
auto bind_one_bool_const = std::bind(
|
||||
&ObjectMember::callback_one_bool_const, &object_member, std::placeholders::_1);
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
bool,
|
||||
rclcpp::function_traits::function_traits<decltype(bind_one_bool_const)>::template
|
||||
argument_type<0>
|
||||
>::value, "Functor accepts a bool as first argument");
|
||||
|
||||
auto bind_two_bools = std::bind(
|
||||
&ObjectMember::callback_two_bools, &object_member, std::placeholders::_1,
|
||||
std::placeholders::_2);
|
||||
@@ -561,6 +577,14 @@ TEST(TestFunctionTraits, check_arguments) {
|
||||
static_assert(
|
||||
rclcpp::function_traits::check_arguments<decltype(bind_one_bool), bool>::value,
|
||||
"Functor accepts a single bool as arguments");
|
||||
|
||||
auto bind_one_bool_const = std::bind(
|
||||
&ObjectMember::callback_one_bool_const, &object_member, std::placeholders::_1);
|
||||
|
||||
// Test std::bind functions
|
||||
static_assert(
|
||||
rclcpp::function_traits::check_arguments<decltype(bind_one_bool_const), bool>::value,
|
||||
"Functor accepts a single bool as arguments");
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -14,10 +14,13 @@
|
||||
|
||||
#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.
|
||||
@@ -34,6 +37,9 @@ public:
|
||||
PublisherBase()
|
||||
: mock_topic_name(""), mock_queue_size(0) {}
|
||||
|
||||
virtual ~PublisherBase()
|
||||
{}
|
||||
|
||||
const char * get_topic_name() const
|
||||
{
|
||||
return mock_topic_name.c_str();
|
||||
@@ -50,6 +56,14 @@ 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;
|
||||
};
|
||||
@@ -71,6 +85,15 @@ 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_;
|
||||
@@ -109,10 +132,9 @@ public:
|
||||
} // namespace mock
|
||||
} // namespace rclcpp
|
||||
|
||||
// Prevent rclcpp/publisher.hpp and rclcpp/subscription.hpp from being imported.
|
||||
#define RCLCPP__PUBLISHER_HPP_
|
||||
#define RCLCPP__SUBSCRIPTION_HPP_
|
||||
#define RCLCPP_BUILDING_LIBRARY 1
|
||||
// Prevent rclcpp/publisher_base.hpp and rclcpp/subscription.hpp from being imported.
|
||||
#define RCLCPP__PUBLISHER_BASE_HPP_
|
||||
#define RCLCPP__SUBSCRIPTION_BASE_HPP_
|
||||
// Force ipm to use our mock publisher class.
|
||||
#define Publisher mock::Publisher
|
||||
#define PublisherBase mock::PublisherBase
|
||||
@@ -155,10 +177,8 @@ TEST(TestIntraProcessManager, nominal) {
|
||||
s1->mock_topic_name = "nominal1";
|
||||
s1->mock_queue_size = 10;
|
||||
|
||||
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 p1_id = ipm.add_publisher(p1);
|
||||
auto p2_id = ipm.add_publisher(p2);
|
||||
auto s1_id = ipm.add_subscription(s1);
|
||||
|
||||
auto ipm_msg = std::make_shared<rcl_interfaces::msg::IntraProcessMessage>();
|
||||
@@ -169,14 +189,14 @@ TEST(TestIntraProcessManager, nominal) {
|
||||
);
|
||||
|
||||
auto p1_m1_original_address = unique_msg.get();
|
||||
auto p1_m1_id = ipm.store_intra_process_message(p1_id, unique_msg);
|
||||
auto p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(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, unique_msg);
|
||||
auto p2_m1_id = ipm.store_intra_process_message(p2_id, std::move(unique_msg));
|
||||
ASSERT_EQ(nullptr, unique_msg);
|
||||
|
||||
ipm.take_intra_process_message(p2_id, p2_m1_id, s1_id, unique_msg);
|
||||
@@ -198,26 +218,22 @@ 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, unique_msg);
|
||||
ipm.store_intra_process_message(p1_id, std::move(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, unique_msg);
|
||||
ipm.store_intra_process_message(p1_id, std::move(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, unique_msg);
|
||||
ASSERT_NE(nullptr, unique_msg);
|
||||
if (unique_msg) {
|
||||
EXPECT_EQ(44ul, unique_msg->message_sequence);
|
||||
EXPECT_EQ(44ul, unique_msg->publisher_id);
|
||||
}
|
||||
ipm.store_intra_process_message(p1_id, std::move(unique_msg));
|
||||
ASSERT_EQ(nullptr, unique_msg);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -240,8 +256,7 @@ TEST(TestIntraProcessManager, remove_publisher_before_trying_to_take) {
|
||||
s1->mock_topic_name = "nominal1";
|
||||
s1->mock_queue_size = 10;
|
||||
|
||||
auto p1_id =
|
||||
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p1);
|
||||
auto p1_id = ipm.add_publisher(p1);
|
||||
auto s1_id = ipm.add_subscription(s1);
|
||||
|
||||
auto ipm_msg = std::make_shared<rcl_interfaces::msg::IntraProcessMessage>();
|
||||
@@ -251,7 +266,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, unique_msg);
|
||||
auto p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
|
||||
ASSERT_EQ(nullptr, unique_msg);
|
||||
|
||||
ipm.remove_publisher(p1_id);
|
||||
@@ -290,8 +305,7 @@ TEST(TestIntraProcessManager, removed_subscription_affects_take) {
|
||||
s3->mock_topic_name = "nominal1";
|
||||
s3->mock_queue_size = 10;
|
||||
|
||||
auto p1_id =
|
||||
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p1);
|
||||
auto p1_id = ipm.add_publisher(p1);
|
||||
auto s1_id = ipm.add_subscription(s1);
|
||||
auto s2_id = ipm.add_subscription(s2);
|
||||
auto s3_id = ipm.add_subscription(s3);
|
||||
@@ -304,7 +318,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, unique_msg);
|
||||
auto p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
|
||||
ASSERT_EQ(nullptr, unique_msg);
|
||||
|
||||
ipm.take_intra_process_message(p1_id, p1_m1_id, s1_id, unique_msg);
|
||||
@@ -361,8 +375,7 @@ TEST(TestIntraProcessManager, multiple_subscriptions_one_publisher) {
|
||||
s3->mock_topic_name = "nominal1";
|
||||
s3->mock_queue_size = 10;
|
||||
|
||||
auto p1_id =
|
||||
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p1);
|
||||
auto p1_id = ipm.add_publisher(p1);
|
||||
auto s1_id = ipm.add_subscription(s1);
|
||||
auto s2_id = ipm.add_subscription(s2);
|
||||
auto s3_id = ipm.add_subscription(s3);
|
||||
@@ -375,7 +388,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, unique_msg);
|
||||
auto p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
|
||||
ASSERT_EQ(nullptr, unique_msg);
|
||||
|
||||
ipm.take_intra_process_message(p1_id, p1_m1_id, s1_id, unique_msg);
|
||||
@@ -437,12 +450,9 @@ TEST(TestIntraProcessManager, multiple_publishers_one_subscription) {
|
||||
s1->mock_topic_name = "nominal1";
|
||||
s1->mock_queue_size = 10;
|
||||
|
||||
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 p1_id = ipm.add_publisher(p1);
|
||||
auto p2_id = ipm.add_publisher(p2);
|
||||
auto p3_id = ipm.add_publisher(p3);
|
||||
auto s1_id = ipm.add_subscription(s1);
|
||||
|
||||
auto ipm_msg = std::make_shared<rcl_interfaces::msg::IntraProcessMessage>();
|
||||
@@ -454,7 +464,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, unique_msg);
|
||||
auto p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
|
||||
ASSERT_EQ(nullptr, unique_msg);
|
||||
|
||||
// Second publish
|
||||
@@ -463,7 +473,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, unique_msg);
|
||||
auto p2_m1_id = ipm.store_intra_process_message(p2_id, std::move(unique_msg));
|
||||
ASSERT_EQ(nullptr, unique_msg);
|
||||
|
||||
// Third publish
|
||||
@@ -472,7 +482,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, unique_msg);
|
||||
auto p3_m1_id = ipm.store_intra_process_message(p3_id, std::move(unique_msg));
|
||||
ASSERT_EQ(nullptr, unique_msg);
|
||||
|
||||
// First take
|
||||
@@ -545,12 +555,9 @@ TEST(TestIntraProcessManager, multiple_publishers_multiple_subscription) {
|
||||
s3->mock_topic_name = "nominal1";
|
||||
s3->mock_queue_size = 10;
|
||||
|
||||
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 p1_id = ipm.add_publisher(p1);
|
||||
auto p2_id = ipm.add_publisher(p2);
|
||||
auto p3_id = ipm.add_publisher(p3);
|
||||
auto s1_id = ipm.add_subscription(s1);
|
||||
auto s2_id = ipm.add_subscription(s2);
|
||||
auto s3_id = ipm.add_subscription(s3);
|
||||
@@ -564,7 +571,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, unique_msg);
|
||||
auto p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
|
||||
ASSERT_EQ(nullptr, unique_msg);
|
||||
|
||||
// Second publish
|
||||
@@ -573,7 +580,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, unique_msg);
|
||||
auto p2_m1_id = ipm.store_intra_process_message(p2_id, std::move(unique_msg));
|
||||
ASSERT_EQ(nullptr, unique_msg);
|
||||
|
||||
// Third publish
|
||||
@@ -582,7 +589,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, unique_msg);
|
||||
auto p3_m1_id = ipm.store_intra_process_message(p3_id, std::move(unique_msg));
|
||||
ASSERT_EQ(nullptr, unique_msg);
|
||||
|
||||
// First take
|
||||
@@ -692,8 +699,7 @@ TEST(TestIntraProcessManager, ring_buffer_displacement) {
|
||||
s1->mock_topic_name = "nominal1";
|
||||
s1->mock_queue_size = 10;
|
||||
|
||||
auto p1_id =
|
||||
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p1);
|
||||
auto p1_id = ipm.add_publisher(p1);
|
||||
auto s1_id = ipm.add_subscription(s1);
|
||||
|
||||
auto ipm_msg = std::make_shared<rcl_interfaces::msg::IntraProcessMessage>();
|
||||
@@ -703,8 +709,7 @@ TEST(TestIntraProcessManager, ring_buffer_displacement) {
|
||||
new rcl_interfaces::msg::IntraProcessMessage(*ipm_msg)
|
||||
);
|
||||
|
||||
auto original_message_pointer1 = unique_msg.get();
|
||||
auto p1_m1_id = ipm.store_intra_process_message(p1_id, unique_msg);
|
||||
auto p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
|
||||
ASSERT_EQ(nullptr, unique_msg);
|
||||
|
||||
ipm_msg->message_sequence = 43;
|
||||
@@ -712,7 +717,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, unique_msg);
|
||||
auto p1_m2_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
|
||||
ASSERT_EQ(nullptr, unique_msg);
|
||||
|
||||
ipm.take_intra_process_message(p1_id, p1_m2_id, s1_id, unique_msg);
|
||||
@@ -728,14 +733,8 @@ 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, 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());
|
||||
}
|
||||
ipm.store_intra_process_message(p1_id, std::move(unique_msg));
|
||||
EXPECT_EQ(nullptr, unique_msg);
|
||||
unique_msg.reset();
|
||||
|
||||
// Since it just got displaced it should no longer be there to take.
|
||||
@@ -759,8 +758,7 @@ TEST(TestIntraProcessManager, subscription_creation_race_condition) {
|
||||
p1->mock_topic_name = "nominal1";
|
||||
p1->mock_queue_size = 2;
|
||||
|
||||
auto p1_id =
|
||||
ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p1);
|
||||
auto p1_id = ipm.add_publisher(p1);
|
||||
|
||||
auto ipm_msg = std::make_shared<rcl_interfaces::msg::IntraProcessMessage>();
|
||||
ipm_msg->message_sequence = 42;
|
||||
@@ -769,7 +767,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, unique_msg);
|
||||
auto p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
|
||||
ASSERT_EQ(nullptr, unique_msg);
|
||||
|
||||
auto s1 = std::make_shared<rclcpp::mock::SubscriptionBase>();
|
||||
@@ -808,7 +806,7 @@ TEST(TestIntraProcessManager, publisher_out_of_scope_take) {
|
||||
p1->mock_topic_name = "nominal1";
|
||||
p1->mock_queue_size = 2;
|
||||
|
||||
p1_id = ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p1);
|
||||
p1_id = ipm.add_publisher(p1);
|
||||
|
||||
auto ipm_msg = std::make_shared<rcl_interfaces::msg::IntraProcessMessage>();
|
||||
ipm_msg->message_sequence = 42;
|
||||
@@ -817,7 +815,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, unique_msg);
|
||||
p1_m1_id = ipm.store_intra_process_message(p1_id, std::move(unique_msg));
|
||||
ASSERT_EQ(nullptr, unique_msg);
|
||||
|
||||
// Explicitly remove publisher from ipm (emulate's publisher's destructor).
|
||||
@@ -847,7 +845,7 @@ TEST(TestIntraProcessManager, publisher_out_of_scope_store) {
|
||||
p1->mock_topic_name = "nominal1";
|
||||
p1->mock_queue_size = 2;
|
||||
|
||||
p1_id = ipm.add_publisher<rcl_interfaces::msg::IntraProcessMessage, std::allocator<void>>(p1);
|
||||
p1_id = ipm.add_publisher(p1);
|
||||
}
|
||||
|
||||
auto ipm_msg = std::make_shared<rcl_interfaces::msg::IntraProcessMessage>();
|
||||
@@ -857,6 +855,6 @@ TEST(TestIntraProcessManager, publisher_out_of_scope_store) {
|
||||
new rcl_interfaces::msg::IntraProcessMessage(*ipm_msg)
|
||||
);
|
||||
|
||||
EXPECT_THROW(ipm.store_intra_process_message(p1_id, unique_msg), std::runtime_error);
|
||||
EXPECT_THROW(ipm.store_intra_process_message(p1_id, std::move(unique_msg)), std::runtime_error);
|
||||
ASSERT_EQ(nullptr, unique_msg);
|
||||
}
|
||||
|
||||
@@ -12,12 +12,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#define RCLCPP_BUILDING_LIBRARY 1 // Prevent including unavailable symbols
|
||||
#include <rclcpp/mapped_ring_buffer.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include "rclcpp/mapped_ring_buffer.hpp"
|
||||
|
||||
/*
|
||||
Tests get_copy and pop on an empty mrb.
|
||||
@@ -28,60 +29,90 @@ 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> actual;
|
||||
mrb.get_copy_at_key(1, actual);
|
||||
EXPECT_EQ(nullptr, actual);
|
||||
std::unique_ptr<char> unique;
|
||||
mrb.get(1, unique);
|
||||
EXPECT_EQ(nullptr, unique);
|
||||
|
||||
mrb.pop_at_key(1, 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);
|
||||
EXPECT_EQ(nullptr, actual);
|
||||
}
|
||||
|
||||
/*
|
||||
Tests push_and_replace with a temporary object.
|
||||
Tests push_and_replace with a temporary object, and using
|
||||
get and pop methods with unique_ptr signature.
|
||||
*/
|
||||
TEST(TestMappedRingBuffer, temporary_l_value) {
|
||||
TEST(TestMappedRingBuffer, temporary_l_value_with_unique_get_pop) {
|
||||
rclcpp::mapped_ring_buffer::MappedRingBuffer<char> mrb(2);
|
||||
// Pass in value with temporary object
|
||||
mrb.push_and_replace(1, std::unique_ptr<char>(new char('a')));
|
||||
mrb.push_and_replace(1, std::shared_ptr<const char>(new char('a')));
|
||||
|
||||
std::unique_ptr<char> actual;
|
||||
mrb.get_copy_at_key(1, actual);
|
||||
mrb.get(1, actual);
|
||||
EXPECT_EQ('a', *actual);
|
||||
|
||||
mrb.pop_at_key(1, actual);
|
||||
mrb.pop(1, actual);
|
||||
EXPECT_EQ('a', *actual);
|
||||
|
||||
mrb.get_copy_at_key(1, actual);
|
||||
mrb.get(1, actual);
|
||||
EXPECT_EQ(nullptr, actual);
|
||||
}
|
||||
|
||||
/*
|
||||
Tests normal usage of the mrb.
|
||||
Using shared push_and_replace, get and pop methods.
|
||||
*/
|
||||
TEST(TestMappedRingBuffer, nominal) {
|
||||
TEST(TestMappedRingBuffer, nominal_push_shared_get_pop_shared) {
|
||||
rclcpp::mapped_ring_buffer::MappedRingBuffer<char> mrb(2);
|
||||
std::unique_ptr<char> expected(new char('a'));
|
||||
// Store expected value's address for later comparison.
|
||||
char * expected_orig = expected.get();
|
||||
std::shared_ptr<const char> expected(new char('a'));
|
||||
|
||||
EXPECT_FALSE(mrb.push_and_replace(1, expected));
|
||||
EXPECT_EQ(2, expected.use_count());
|
||||
|
||||
std::unique_ptr<char> actual;
|
||||
mrb.get_copy_at_key(1, actual);
|
||||
std::shared_ptr<const char> actual;
|
||||
mrb.get(1, actual);
|
||||
EXPECT_NE(nullptr, actual);
|
||||
if (actual) {
|
||||
EXPECT_EQ('a', *actual);
|
||||
}
|
||||
EXPECT_NE(expected_orig, actual.get());
|
||||
EXPECT_EQ(expected, actual);
|
||||
EXPECT_EQ(3, actual.use_count());
|
||||
|
||||
mrb.pop_at_key(1, actual);
|
||||
EXPECT_NE(nullptr, actual);
|
||||
mrb.pop(1, actual);
|
||||
EXPECT_EQ(expected, actual);
|
||||
if (actual) {
|
||||
EXPECT_EQ('a', *actual);
|
||||
}
|
||||
EXPECT_EQ(expected_orig, actual.get());
|
||||
expected.reset();
|
||||
EXPECT_TRUE(actual.unique());
|
||||
|
||||
mrb.get_copy_at_key(1, actual);
|
||||
mrb.get(1, actual);
|
||||
EXPECT_EQ(nullptr, actual);
|
||||
|
||||
expected.reset(new char('a'));
|
||||
@@ -93,16 +124,16 @@ TEST(TestMappedRingBuffer, nominal) {
|
||||
expected.reset(new char('c'));
|
||||
EXPECT_TRUE(mrb.push_and_replace(3, expected));
|
||||
|
||||
mrb.get_copy_at_key(1, actual);
|
||||
mrb.get(1, actual);
|
||||
EXPECT_EQ(nullptr, actual);
|
||||
|
||||
mrb.get_copy_at_key(2, actual);
|
||||
mrb.get(2, actual);
|
||||
EXPECT_NE(nullptr, actual);
|
||||
if (actual) {
|
||||
EXPECT_EQ('b', *actual);
|
||||
}
|
||||
|
||||
mrb.get_copy_at_key(3, actual);
|
||||
mrb.get(3, actual);
|
||||
EXPECT_NE(nullptr, actual);
|
||||
if (actual) {
|
||||
EXPECT_EQ('c', *actual);
|
||||
@@ -110,40 +141,167 @@ TEST(TestMappedRingBuffer, nominal) {
|
||||
}
|
||||
|
||||
/*
|
||||
Tests get_ownership on a normal mrb.
|
||||
Tests normal usage of the mrb.
|
||||
Using shared push_and_replace, unique get and pop methods.
|
||||
*/
|
||||
TEST(TestMappedRingBuffer, get_ownership) {
|
||||
TEST(TestMappedRingBuffer, nominal_push_shared_get_pop_unique) {
|
||||
rclcpp::mapped_ring_buffer::MappedRingBuffer<char> mrb(2);
|
||||
std::unique_ptr<char> expected(new char('a'));
|
||||
// Store expected value's address for later comparison.
|
||||
char * expected_orig = expected.get();
|
||||
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_copy_at_key(1, 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);
|
||||
|
||||
mrb.get_ownership_at_key(1, 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) {
|
||||
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::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);
|
||||
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);
|
||||
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);
|
||||
|
||||
mrb.pop_at_key(1, 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('a', *actual); // The value should be the same.
|
||||
EXPECT_EQ('b', *actual);
|
||||
}
|
||||
EXPECT_NE(expected_orig, actual.get()); // Even though we pop'ed, we didn't get the original.
|
||||
|
||||
mrb.get_copy_at_key(1, actual);
|
||||
EXPECT_EQ(nullptr, actual);
|
||||
mrb.get(3, actual);
|
||||
EXPECT_NE(nullptr, actual);
|
||||
if (actual) {
|
||||
EXPECT_EQ('c', *actual);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -152,22 +310,23 @@ TEST(TestMappedRingBuffer, get_ownership) {
|
||||
TEST(TestMappedRingBuffer, non_unique_keys) {
|
||||
rclcpp::mapped_ring_buffer::MappedRingBuffer<char> mrb(2);
|
||||
|
||||
std::unique_ptr<char> input(new char('a'));
|
||||
std::shared_ptr<const 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_at_key(1, actual);
|
||||
mrb.pop(1, actual);
|
||||
EXPECT_NE(nullptr, actual);
|
||||
if (actual) {
|
||||
EXPECT_EQ('a', *actual);
|
||||
}
|
||||
|
||||
actual = nullptr;
|
||||
mrb.pop_at_key(1, actual);
|
||||
mrb.pop(1, actual);
|
||||
EXPECT_NE(nullptr, actual);
|
||||
if (actual) {
|
||||
EXPECT_EQ('b', *actual);
|
||||
|
||||
@@ -14,9 +14,10 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
@@ -99,6 +100,23 @@ TEST_F(TestNode, get_name_and_namespace) {
|
||||
EXPECT_STREQ("/my/ns", node->get_namespace());
|
||||
EXPECT_STREQ("/my/ns/my_node", node->get_fully_qualified_name());
|
||||
}
|
||||
{
|
||||
auto node1 = std::make_shared<rclcpp::Node>("my_node1", "my/ns");
|
||||
auto node2 = std::make_shared<rclcpp::Node>("my_node2", "my/ns");
|
||||
auto node3 = std::make_shared<rclcpp::Node>("my_node3", "/ns2");
|
||||
auto node4 = std::make_shared<rclcpp::Node>("my_node4", "my/ns3");
|
||||
auto names_and_namespaces = node1->get_node_names();
|
||||
auto name_namespace_set = std::unordered_set<std::string>(names_and_namespaces.begin(),
|
||||
names_and_namespaces.end());
|
||||
std::function<bool(std::string)> Set_Contains = [&](std::string string_key)
|
||||
{
|
||||
return name_namespace_set.find(string_key) != name_namespace_set.end();
|
||||
};
|
||||
EXPECT_TRUE(Set_Contains("/my/ns/my_node1"));
|
||||
EXPECT_TRUE(Set_Contains("/my/ns/my_node2"));
|
||||
EXPECT_TRUE(Set_Contains("/ns2/my_node3"));
|
||||
EXPECT_TRUE(Set_Contains("/my/ns3/my_node4"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestNode, subnode_get_name_and_namespace) {
|
||||
@@ -347,8 +365,10 @@ TEST_F(TestNode, declare_parameter_with_no_initial_values) {
|
||||
TEST_F(TestNode, declare_parameter_with_initial_values) {
|
||||
// test cases with initial values
|
||||
rclcpp::NodeOptions no;
|
||||
no.initial_parameters({
|
||||
no.parameter_overrides({
|
||||
{"parameter_no_default", 42},
|
||||
{"parameter_no_default_set", 42},
|
||||
{"parameter_no_default_set_cvref", 42},
|
||||
{"parameter_and_default", 42},
|
||||
{"parameter_custom", 42},
|
||||
{"parameter_template", 42},
|
||||
@@ -363,6 +383,25 @@ TEST_F(TestNode, declare_parameter_with_initial_values) {
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER);
|
||||
EXPECT_EQ(value.get<int>(), 42);
|
||||
}
|
||||
{
|
||||
// no default, with initial, and set after
|
||||
rclcpp::ParameterValue value = node->declare_parameter("parameter_no_default_set");
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER);
|
||||
EXPECT_EQ(value.get<int>(), 42);
|
||||
// check that the value is changed after a set
|
||||
node->set_parameter({"parameter_no_default_set", 44});
|
||||
EXPECT_EQ(node->get_parameter("parameter_no_default_set").get_value<int>(), 44);
|
||||
}
|
||||
{
|
||||
// no default, with initial
|
||||
const rclcpp::ParameterValue & value =
|
||||
node->declare_parameter("parameter_no_default_set_cvref");
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER);
|
||||
EXPECT_EQ(value.get<int>(), 42);
|
||||
// check that the value is changed after a set
|
||||
node->set_parameter({"parameter_no_default_set_cvref", 44});
|
||||
EXPECT_EQ(value.get<int>(), 44);
|
||||
}
|
||||
{
|
||||
// int default, with initial
|
||||
rclcpp::ParameterValue default_value(43);
|
||||
@@ -677,12 +716,370 @@ TEST_F(TestNode, set_parameter_undeclared_parameters_not_allowed) {
|
||||
|
||||
EXPECT_FALSE(node->has_parameter(name));
|
||||
}
|
||||
{
|
||||
// setting a parameter with integer range descriptor
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.integer_range.resize(1);
|
||||
auto & integer_range = descriptor.integer_range.at(0);
|
||||
integer_range.from_value = 10;
|
||||
integer_range.to_value = 18;
|
||||
integer_range.step = 2;
|
||||
node->declare_parameter(name, 10, descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER);
|
||||
EXPECT_EQ(value.get_value<int64_t>(), 10);
|
||||
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 14)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 14);
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 18)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 18);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 15)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 18);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 20)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 18);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 8)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 18);
|
||||
}
|
||||
{
|
||||
// setting a parameter with integer range descriptor, from_value > to_value
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.integer_range.resize(1);
|
||||
auto & integer_range = descriptor.integer_range.at(0);
|
||||
integer_range.from_value = 20;
|
||||
integer_range.to_value = 18;
|
||||
integer_range.step = 1;
|
||||
node->declare_parameter(name, 20, descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER);
|
||||
EXPECT_EQ(value.get_value<int64_t>(), 20);
|
||||
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 18)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 18);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 19)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 18);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 10)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 18);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 25)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 18);
|
||||
}
|
||||
{
|
||||
// setting a parameter with integer range descriptor, from_value = to_value
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.integer_range.resize(1);
|
||||
auto & integer_range = descriptor.integer_range.at(0);
|
||||
integer_range.from_value = 18;
|
||||
integer_range.to_value = 18;
|
||||
integer_range.step = 1;
|
||||
node->declare_parameter(name, 18, descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER);
|
||||
EXPECT_EQ(value.get_value<int64_t>(), 18);
|
||||
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 17)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 18);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 19)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 18);
|
||||
}
|
||||
{
|
||||
// setting a parameter with integer range descriptor, step > distance(from_value, to_value)
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.integer_range.resize(1);
|
||||
auto & integer_range = descriptor.integer_range.at(0);
|
||||
integer_range.from_value = 18;
|
||||
integer_range.to_value = 25;
|
||||
integer_range.step = 10;
|
||||
node->declare_parameter(name, 18, descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER);
|
||||
EXPECT_EQ(value.get_value<int64_t>(), 18);
|
||||
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 25)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 25);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 17)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 25);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 19)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 25);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 26)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 25);
|
||||
}
|
||||
{
|
||||
// setting a parameter with integer range descriptor, distance not multiple of the step.
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.integer_range.resize(1);
|
||||
auto & integer_range = descriptor.integer_range.at(0);
|
||||
integer_range.from_value = 18;
|
||||
integer_range.to_value = 28;
|
||||
integer_range.step = 7;
|
||||
node->declare_parameter(name, 18, descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER);
|
||||
EXPECT_EQ(value.get_value<int64_t>(), 18);
|
||||
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 28)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 28);
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 25)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 25);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 17)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 25);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 19)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 25);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 32)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 25);
|
||||
}
|
||||
{
|
||||
// setting a parameter with integer range descriptor, step=0
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.integer_range.resize(1);
|
||||
auto & integer_range = descriptor.integer_range.at(0);
|
||||
integer_range.from_value = 10;
|
||||
integer_range.to_value = 18;
|
||||
integer_range.step = 0;
|
||||
node->declare_parameter(name, 10, descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER);
|
||||
EXPECT_EQ(value.get_value<int64_t>(), 10);
|
||||
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 11)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 11);
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 15)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 15);
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 18)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 18);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 9)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 18);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 19)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int64_t>(), 18);
|
||||
}
|
||||
{
|
||||
// setting a parameter with integer range descriptor and wrong default value will throw
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.integer_range.resize(1);
|
||||
auto & integer_range = descriptor.integer_range.at(0);
|
||||
integer_range.from_value = 10;
|
||||
integer_range.to_value = 18;
|
||||
integer_range.step = 2;
|
||||
ASSERT_THROW(
|
||||
node->declare_parameter(name, 42, descriptor),
|
||||
rclcpp::exceptions::InvalidParameterValueException);
|
||||
}
|
||||
{
|
||||
// setting a parameter with floating point range descriptor
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.floating_point_range.resize(1);
|
||||
auto & floating_point_range = descriptor.floating_point_range.at(0);
|
||||
floating_point_range.from_value = 10.0;
|
||||
floating_point_range.to_value = 11.0;
|
||||
floating_point_range.step = 0.2;
|
||||
node->declare_parameter(name, 10.0, descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE);
|
||||
EXPECT_EQ(value.get_value<double>(), 10.0);
|
||||
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 10.2)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 10.2);
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 11.0)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 11.3)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 12.0)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 9.4)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
}
|
||||
{
|
||||
// setting a parameter with floating point range descriptor, negative step
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.floating_point_range.resize(1);
|
||||
auto & floating_point_range = descriptor.floating_point_range.at(0);
|
||||
floating_point_range.from_value = 10.0;
|
||||
floating_point_range.to_value = 11.0;
|
||||
floating_point_range.step = -0.2;
|
||||
node->declare_parameter(name, 10.0, descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE);
|
||||
EXPECT_EQ(value.get_value<double>(), 10.0);
|
||||
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 10.2)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 10.2);
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 11.0)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 11.3)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 12.0)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 9.4)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
}
|
||||
{
|
||||
// setting a parameter with floating point range descriptor, from_value > to_value
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.floating_point_range.resize(1);
|
||||
auto & floating_point_range = descriptor.floating_point_range.at(0);
|
||||
floating_point_range.from_value = 11.0;
|
||||
floating_point_range.to_value = 10.0;
|
||||
floating_point_range.step = 0.2;
|
||||
node->declare_parameter(name, 10.0, descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE);
|
||||
EXPECT_EQ(value.get_value<double>(), 10.0);
|
||||
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 11.0)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 11.2)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 12.0)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 9.4)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
}
|
||||
{
|
||||
// setting a parameter with floating point range descriptor, from_value = to_value
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.floating_point_range.resize(1);
|
||||
auto & floating_point_range = descriptor.floating_point_range.at(0);
|
||||
floating_point_range.from_value = 10.0;
|
||||
floating_point_range.to_value = 10.0;
|
||||
floating_point_range.step = 0.2;
|
||||
node->declare_parameter(name, 10.0, descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE);
|
||||
EXPECT_EQ(value.get_value<double>(), 10.0);
|
||||
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 11.2)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 10.0);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 12.0)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 10.0);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 9.4)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 10.0);
|
||||
}
|
||||
{
|
||||
// setting a parameter with floating point range descriptor, step > distance
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.floating_point_range.resize(1);
|
||||
auto & floating_point_range = descriptor.floating_point_range.at(0);
|
||||
floating_point_range.from_value = 10.0;
|
||||
floating_point_range.to_value = 11.0;
|
||||
floating_point_range.step = 2.2;
|
||||
node->declare_parameter(name, 10.0, descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE);
|
||||
EXPECT_EQ(value.get_value<double>(), 10.0);
|
||||
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 11.0)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 12.2)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 7.8)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
}
|
||||
{
|
||||
// setting a parameter with floating point range descriptor, distance not multiple of the step.
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.floating_point_range.resize(1);
|
||||
auto & floating_point_range = descriptor.floating_point_range.at(0);
|
||||
floating_point_range.from_value = 10.0;
|
||||
floating_point_range.to_value = 11.0;
|
||||
floating_point_range.step = 0.7;
|
||||
node->declare_parameter(name, 10.0, descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE);
|
||||
EXPECT_EQ(value.get_value<double>(), 10.0);
|
||||
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 11.0)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 10.7)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 10.7);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 11.4)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 10.7);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 9.3)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 10.7);
|
||||
}
|
||||
{
|
||||
// setting a parameter with floating point range descriptor, step=0
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.floating_point_range.resize(1);
|
||||
auto & floating_point_range = descriptor.floating_point_range.at(0);
|
||||
floating_point_range.from_value = 10.0;
|
||||
floating_point_range.to_value = 11.0;
|
||||
floating_point_range.step = 0.0;
|
||||
node->declare_parameter(name, 10.0, descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE);
|
||||
EXPECT_EQ(value.get_value<double>(), 10.0);
|
||||
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 10.0001)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 10.0001);
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 10.5479051)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 10.5479051);
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 11.0)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 11.001)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 9.999)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
}
|
||||
{
|
||||
// setting a parameter with a different type is still possible
|
||||
// when having a descriptor specifying a type (type is a status, not a constraint).
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.type = rclcpp::PARAMETER_INTEGER;
|
||||
node->declare_parameter(name, 42, descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER);
|
||||
EXPECT_EQ(value.get_value<int64_t>(), 42);
|
||||
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, "asd")).successful);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_STRING);
|
||||
EXPECT_EQ(value.get_value<std::string>(), "asd");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestNode, set_parameter_undeclared_parameters_allowed) {
|
||||
auto node = std::make_shared<rclcpp::Node>(
|
||||
"test_set_parameter_node"_unq,
|
||||
rclcpp::NodeOptions().allow_undeclared_parameters(true));
|
||||
rclcpp::NodeOptions no;
|
||||
no.parameter_overrides({
|
||||
{"parameter_with_override", 30},
|
||||
});
|
||||
no.allow_undeclared_parameters(true);
|
||||
auto node = std::make_shared<rclcpp::Node>("test_set_parameter_node"_unq, no);
|
||||
{
|
||||
// overrides are ignored when not declaring a parameter
|
||||
auto name = "parameter_with_override";
|
||||
EXPECT_FALSE(node->has_parameter(name));
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 43)).successful);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int>(), 43);
|
||||
}
|
||||
{
|
||||
// normal use (declare first) still works with this true
|
||||
auto name = "parameter"_unq;
|
||||
|
||||
@@ -32,7 +32,7 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
TEST(TestParameter, not_set_variant) {
|
||||
TEST_F(TestParameter, not_set_variant) {
|
||||
// Direct instantiation
|
||||
rclcpp::Parameter not_set_variant;
|
||||
EXPECT_EQ(rclcpp::PARAMETER_NOT_SET, not_set_variant.get_type());
|
||||
@@ -57,7 +57,7 @@ TEST(TestParameter, not_set_variant) {
|
||||
rclcpp::Parameter::from_parameter_msg(not_set_param).get_type());
|
||||
}
|
||||
|
||||
TEST(TestParameter, bool_variant) {
|
||||
TEST_F(TestParameter, bool_variant) {
|
||||
// Direct instantiation
|
||||
rclcpp::Parameter bool_variant_true("bool_param", true);
|
||||
EXPECT_EQ("bool_param", bool_variant_true.get_name());
|
||||
@@ -111,7 +111,7 @@ TEST(TestParameter, bool_variant) {
|
||||
bool_variant_false.get_value_message().type);
|
||||
}
|
||||
|
||||
TEST(TestParameter, integer_variant) {
|
||||
TEST_F(TestParameter, integer_variant) {
|
||||
const int TEST_VALUE {42};
|
||||
|
||||
// Direct instantiation
|
||||
@@ -155,7 +155,7 @@ TEST(TestParameter, integer_variant) {
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
TEST(TestParameter, long_integer_variant) {
|
||||
TEST_F(TestParameter, long_integer_variant) {
|
||||
const int64_t TEST_VALUE {std::numeric_limits<int64_t>::max()};
|
||||
|
||||
// Direct instantiation
|
||||
@@ -199,7 +199,7 @@ TEST(TestParameter, long_integer_variant) {
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
TEST(TestParameter, float_variant) {
|
||||
TEST_F(TestParameter, float_variant) {
|
||||
const float TEST_VALUE {42.0f};
|
||||
|
||||
// Direct instantiation
|
||||
@@ -243,7 +243,7 @@ TEST(TestParameter, float_variant) {
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
TEST(TestParameter, double_variant) {
|
||||
TEST_F(TestParameter, double_variant) {
|
||||
const double TEST_VALUE {-42.1};
|
||||
|
||||
// Direct instantiation
|
||||
@@ -287,7 +287,7 @@ TEST(TestParameter, double_variant) {
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
TEST(TestParameter, string_variant) {
|
||||
TEST_F(TestParameter, string_variant) {
|
||||
const std::string TEST_VALUE {"ROS2"};
|
||||
|
||||
// Direct instantiation
|
||||
@@ -330,7 +330,7 @@ TEST(TestParameter, string_variant) {
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
TEST(TestParameter, byte_array_variant) {
|
||||
TEST_F(TestParameter, byte_array_variant) {
|
||||
const std::vector<uint8_t> TEST_VALUE {0x52, 0x4f, 0x53, 0x32};
|
||||
|
||||
// Direct instantiation
|
||||
@@ -374,7 +374,7 @@ TEST(TestParameter, byte_array_variant) {
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
TEST(TestParameter, bool_array_variant) {
|
||||
TEST_F(TestParameter, bool_array_variant) {
|
||||
const std::vector<bool> TEST_VALUE {false, true, true, false, false, true};
|
||||
|
||||
// Direct instantiation
|
||||
@@ -418,7 +418,7 @@ TEST(TestParameter, bool_array_variant) {
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
TEST(TestParameter, integer_array_variant) {
|
||||
TEST_F(TestParameter, integer_array_variant) {
|
||||
const std::vector<int> TEST_VALUE
|
||||
{42, -99, std::numeric_limits<int>::max(), std::numeric_limits<int>::lowest(), 0};
|
||||
|
||||
@@ -493,7 +493,7 @@ TEST(TestParameter, integer_array_variant) {
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER_ARRAY);
|
||||
}
|
||||
|
||||
TEST(TestParameter, long_integer_array_variant) {
|
||||
TEST_F(TestParameter, long_integer_array_variant) {
|
||||
const std::vector<int64_t> TEST_VALUE
|
||||
{42, -99, std::numeric_limits<int64_t>::max(), std::numeric_limits<int64_t>::lowest(), 0};
|
||||
|
||||
@@ -541,7 +541,7 @@ TEST(TestParameter, long_integer_array_variant) {
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
TEST(TestParameter, float_array_variant) {
|
||||
TEST_F(TestParameter, float_array_variant) {
|
||||
const std::vector<float> TEST_VALUE
|
||||
{42.1f, -99.1f, std::numeric_limits<float>::max(), std::numeric_limits<float>::lowest(), 0.1f};
|
||||
|
||||
@@ -616,7 +616,7 @@ TEST(TestParameter, float_array_variant) {
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
TEST(TestParameter, double_array_variant) {
|
||||
TEST_F(TestParameter, double_array_variant) {
|
||||
const std::vector<double> TEST_VALUE
|
||||
{42.1, -99.1, std::numeric_limits<double>::max(), std::numeric_limits<double>::lowest(), 0.1};
|
||||
|
||||
@@ -664,7 +664,7 @@ TEST(TestParameter, double_array_variant) {
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
TEST(TestParameter, string_array_variant) {
|
||||
TEST_F(TestParameter, string_array_variant) {
|
||||
const std::vector<std::string> TEST_VALUE {"R", "O", "S2"};
|
||||
|
||||
// Direct instantiation
|
||||
|
||||
155
rclcpp/test/test_parameter_client.cpp
Normal file
155
rclcpp/test/test_parameter_client.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
#include "rcl_interfaces/msg/parameter_event.hpp"
|
||||
|
||||
class TestParameterClient : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
void OnMessage(const rcl_interfaces::msg::ParameterEvent::SharedPtr event)
|
||||
{
|
||||
(void)event;
|
||||
}
|
||||
|
||||
protected:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
|
||||
void SetUp()
|
||||
{
|
||||
node = std::make_shared<rclcpp::Node>("test_parameter_client", "/ns");
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
{
|
||||
node.reset();
|
||||
}
|
||||
|
||||
rclcpp::Node::SharedPtr node;
|
||||
};
|
||||
|
||||
/*
|
||||
Testing async parameter client construction and destruction.
|
||||
*/
|
||||
TEST_F(TestParameterClient, async_construction_and_destruction) {
|
||||
{
|
||||
auto asynchronous_client = std::make_shared<rclcpp::AsyncParametersClient>(node);
|
||||
(void)asynchronous_client;
|
||||
}
|
||||
|
||||
{
|
||||
auto asynchronous_client = std::make_shared<rclcpp::AsyncParametersClient>(
|
||||
node->get_node_base_interface(),
|
||||
node->get_node_topics_interface(),
|
||||
node->get_node_graph_interface(),
|
||||
node->get_node_services_interface());
|
||||
(void)asynchronous_client;
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
std::make_shared<rclcpp::AsyncParametersClient>(node, "invalid_remote_node?");
|
||||
}, rclcpp::exceptions::InvalidServiceNameError);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Testing sync parameter client construction and destruction.
|
||||
*/
|
||||
TEST_F(TestParameterClient, sync_construction_and_destruction) {
|
||||
{
|
||||
auto synchronous_client = std::make_shared<rclcpp::SyncParametersClient>(node);
|
||||
(void)synchronous_client;
|
||||
}
|
||||
|
||||
{
|
||||
auto synchronous_client = std::make_shared<rclcpp::SyncParametersClient>(
|
||||
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(),
|
||||
node);
|
||||
(void)synchronous_client;
|
||||
}
|
||||
|
||||
{
|
||||
auto synchronous_client = std::make_shared<rclcpp::SyncParametersClient>(
|
||||
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(),
|
||||
node->get_node_base_interface(),
|
||||
node->get_node_topics_interface(),
|
||||
node->get_node_graph_interface(),
|
||||
node->get_node_services_interface());
|
||||
(void)synchronous_client;
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
std::make_shared<rclcpp::SyncParametersClient>(node, "invalid_remote_node?");
|
||||
}, rclcpp::exceptions::InvalidServiceNameError);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Testing different methods for parameter event subscription from asynchronous clients.
|
||||
*/
|
||||
TEST_F(TestParameterClient, async_parameter_event_subscription) {
|
||||
auto callback = std::bind(&TestParameterClient::OnMessage, this, std::placeholders::_1);
|
||||
{
|
||||
auto asynchronous_client = std::make_shared<rclcpp::AsyncParametersClient>(node);
|
||||
auto event_sub = asynchronous_client->on_parameter_event(callback);
|
||||
(void)event_sub;
|
||||
}
|
||||
|
||||
{
|
||||
auto event_sub = rclcpp::AsyncParametersClient::on_parameter_event(node, callback);
|
||||
(void)event_sub;
|
||||
}
|
||||
|
||||
{
|
||||
auto event_sub = rclcpp::AsyncParametersClient::on_parameter_event(
|
||||
node->get_node_topics_interface(),
|
||||
callback);
|
||||
(void)event_sub;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Testing different methods for parameter event subscription from synchronous clients.
|
||||
*/
|
||||
TEST_F(TestParameterClient, sync_parameter_event_subscription) {
|
||||
auto callback = std::bind(&TestParameterClient::OnMessage, this, std::placeholders::_1);
|
||||
{
|
||||
auto synchronous_client = std::make_shared<rclcpp::SyncParametersClient>(node);
|
||||
auto event_sub = synchronous_client->on_parameter_event(callback);
|
||||
(void)event_sub;
|
||||
}
|
||||
|
||||
{
|
||||
auto event_sub = rclcpp::SyncParametersClient::on_parameter_event(node, callback);
|
||||
(void)event_sub;
|
||||
}
|
||||
|
||||
{
|
||||
auto event_sub = rclcpp::SyncParametersClient::on_parameter_event(
|
||||
node->get_node_topics_interface(),
|
||||
callback);
|
||||
(void)event_sub;
|
||||
}
|
||||
}
|
||||
@@ -1,70 +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 <string>
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "test_msgs/msg/empty.hpp"
|
||||
|
||||
class TestPubSubOptionAPI : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
|
||||
void SetUp()
|
||||
{
|
||||
node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
{
|
||||
node.reset();
|
||||
}
|
||||
|
||||
rclcpp::Node::SharedPtr node;
|
||||
};
|
||||
|
||||
TEST_F(TestPubSubOptionAPI, check_for_ambiguous) {
|
||||
rclcpp::PublisherOptions pub_options;
|
||||
rclcpp::SubscriptionOptions sub_options;
|
||||
|
||||
auto topic_only_pub = node->create_publisher<test_msgs::msg::Empty>(
|
||||
"topic_only");
|
||||
auto topic_depth_pub = node->create_publisher<test_msgs::msg::Empty>(
|
||||
"topic_depth",
|
||||
10);
|
||||
auto all_options_pub = node->create_publisher<test_msgs::msg::Empty>(
|
||||
"topic_options",
|
||||
10,
|
||||
pub_options);
|
||||
|
||||
auto topic_only_sub = node->create_subscription<test_msgs::msg::Empty>(
|
||||
"topic_only",
|
||||
[](std::shared_ptr<test_msgs::msg::Empty>) {});
|
||||
auto topic_depth_sub = node->create_subscription<test_msgs::msg::Empty>(
|
||||
"topic_depth",
|
||||
[](std::shared_ptr<test_msgs::msg::Empty>) {},
|
||||
10);
|
||||
auto all_options_sub = node->create_subscription<test_msgs::msg::Empty>(
|
||||
"topic_options",
|
||||
[](std::shared_ptr<test_msgs::msg::Empty>) {},
|
||||
10,
|
||||
sub_options);
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
@@ -24,12 +25,13 @@
|
||||
|
||||
class TestPublisher : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
|
||||
protected:
|
||||
void initialize(const rclcpp::NodeOptions & node_options = rclcpp::NodeOptions())
|
||||
{
|
||||
node = std::make_shared<rclcpp::Node>("my_node", "/ns", node_options);
|
||||
@@ -43,6 +45,25 @@ protected:
|
||||
rclcpp::Node::SharedPtr node;
|
||||
};
|
||||
|
||||
struct TestParameters
|
||||
{
|
||||
TestParameters(rclcpp::QoS qos, std::string description)
|
||||
: qos(qos), description(description) {}
|
||||
rclcpp::QoS qos;
|
||||
std::string description;
|
||||
};
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, const TestParameters & params)
|
||||
{
|
||||
out << params.description;
|
||||
return out;
|
||||
}
|
||||
|
||||
class TestPublisherInvalidIntraprocessQos
|
||||
: public TestPublisher,
|
||||
public ::testing::WithParamInterface<TestParameters>
|
||||
{};
|
||||
|
||||
class TestPublisherSub : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
@@ -65,14 +86,6 @@ protected:
|
||||
rclcpp::Node::SharedPtr subnode;
|
||||
};
|
||||
|
||||
static constexpr rmw_qos_profile_t invalid_qos_profile()
|
||||
{
|
||||
rmw_qos_profile_t profile = rmw_qos_profile_default;
|
||||
profile.depth = 1;
|
||||
profile.durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
|
||||
return profile;
|
||||
}
|
||||
|
||||
/*
|
||||
Testing publisher construction and destruction.
|
||||
*/
|
||||
@@ -80,50 +93,148 @@ TEST_F(TestPublisher, construction_and_destruction) {
|
||||
initialize();
|
||||
using rcl_interfaces::msg::IntraProcessMessage;
|
||||
{
|
||||
auto publisher = node->create_publisher<IntraProcessMessage>("topic");
|
||||
auto publisher = node->create_publisher<IntraProcessMessage>("topic", 42);
|
||||
(void)publisher;
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
auto publisher = node->create_publisher<IntraProcessMessage>("invalid_topic?");
|
||||
auto publisher = node->create_publisher<IntraProcessMessage>("invalid_topic?", 42);
|
||||
}, rclcpp::exceptions::InvalidTopicNameError);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Testing publisher creation signatures.
|
||||
*/
|
||||
TEST_F(TestPublisher, various_creation_signatures) {
|
||||
initialize();
|
||||
using rcl_interfaces::msg::IntraProcessMessage;
|
||||
{
|
||||
auto publisher = node->create_publisher<IntraProcessMessage>("topic", 42);
|
||||
(void)publisher;
|
||||
}
|
||||
{
|
||||
auto publisher = node->create_publisher<IntraProcessMessage>("topic", rclcpp::QoS(42));
|
||||
(void)publisher;
|
||||
}
|
||||
{
|
||||
auto publisher =
|
||||
node->create_publisher<IntraProcessMessage>("topic", rclcpp::QoS(rclcpp::KeepLast(42)));
|
||||
(void)publisher;
|
||||
}
|
||||
{
|
||||
auto publisher =
|
||||
node->create_publisher<IntraProcessMessage>("topic", rclcpp::QoS(rclcpp::KeepAll()));
|
||||
(void)publisher;
|
||||
}
|
||||
{
|
||||
auto publisher =
|
||||
node->create_publisher<IntraProcessMessage>("topic", 42, rclcpp::PublisherOptions());
|
||||
(void)publisher;
|
||||
}
|
||||
{
|
||||
auto publisher =
|
||||
rclcpp::create_publisher<IntraProcessMessage>(node, "topic", 42, rclcpp::PublisherOptions());
|
||||
(void)publisher;
|
||||
}
|
||||
// Now deprecated functions.
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
{
|
||||
auto publisher = node->create_publisher<IntraProcessMessage>("topic");
|
||||
(void)publisher;
|
||||
}
|
||||
{
|
||||
auto publisher = node->create_publisher<IntraProcessMessage>(
|
||||
"topic",
|
||||
42,
|
||||
std::make_shared<std::allocator<IntraProcessMessage>>());
|
||||
(void)publisher;
|
||||
}
|
||||
{
|
||||
auto publisher = node->create_publisher<IntraProcessMessage>("topic", rmw_qos_profile_default);
|
||||
(void)publisher;
|
||||
}
|
||||
{
|
||||
auto publisher = node->create_publisher<IntraProcessMessage>(
|
||||
"topic",
|
||||
rmw_qos_profile_default,
|
||||
std::make_shared<std::allocator<IntraProcessMessage>>());
|
||||
(void)publisher;
|
||||
}
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic pop
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
Testing publisher with intraprocess enabled and invalid QoS
|
||||
*/
|
||||
TEST_F(TestPublisher, intraprocess_with_invalid_qos) {
|
||||
TEST_P(TestPublisherInvalidIntraprocessQos, test_publisher_throws) {
|
||||
initialize(rclcpp::NodeOptions().use_intra_process_comms(true));
|
||||
rmw_qos_profile_t qos = invalid_qos_profile();
|
||||
rclcpp::QoS qos = GetParam().qos;
|
||||
using rcl_interfaces::msg::IntraProcessMessage;
|
||||
{
|
||||
ASSERT_THROW(
|
||||
{auto publisher = node->create_publisher<IntraProcessMessage>("topic", qos);},
|
||||
rclcpp::exceptions::InvalidParametersException);
|
||||
std::invalid_argument);
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<TestParameters> invalid_qos_profiles()
|
||||
{
|
||||
std::vector<TestParameters> parameters;
|
||||
|
||||
parameters.reserve(3);
|
||||
parameters.push_back(
|
||||
TestParameters(
|
||||
rclcpp::QoS(rclcpp::KeepLast(10)).transient_local(),
|
||||
"transient_local_qos"));
|
||||
parameters.push_back(
|
||||
TestParameters(
|
||||
rclcpp::QoS(rclcpp::KeepLast(0)),
|
||||
"keep_last_qos_with_zero_history_depth"));
|
||||
parameters.push_back(
|
||||
TestParameters(
|
||||
rclcpp::QoS(rclcpp::KeepAll()),
|
||||
"keep_all_qos"));
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
TestPublisherThrows, TestPublisherInvalidIntraprocessQos,
|
||||
::testing::ValuesIn(invalid_qos_profiles()),
|
||||
::testing::PrintToStringParamName());
|
||||
|
||||
/*
|
||||
Testing publisher construction and destruction for subnodes.
|
||||
*/
|
||||
TEST_F(TestPublisherSub, construction_and_destruction) {
|
||||
using rcl_interfaces::msg::IntraProcessMessage;
|
||||
{
|
||||
auto publisher = subnode->create_publisher<IntraProcessMessage>("topic");
|
||||
auto publisher = subnode->create_publisher<IntraProcessMessage>("topic", 42);
|
||||
|
||||
EXPECT_STREQ(publisher->get_topic_name(), "/ns/sub_ns/topic");
|
||||
}
|
||||
|
||||
{
|
||||
auto publisher = subnode->create_publisher<IntraProcessMessage>("/topic");
|
||||
auto publisher = subnode->create_publisher<IntraProcessMessage>("/topic", 42);
|
||||
|
||||
EXPECT_STREQ(publisher->get_topic_name(), "/topic");
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
auto publisher = subnode->create_publisher<IntraProcessMessage>("invalid_topic?");
|
||||
auto publisher = subnode->create_publisher<IntraProcessMessage>("invalid_topic?", 42);
|
||||
}, rclcpp::exceptions::InvalidTopicNameError);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,12 +74,12 @@ TEST_P(TestPublisherSubscriptionCount, increasing_and_decreasing_counts)
|
||||
"my_node",
|
||||
"/ns",
|
||||
parameters.node_options[0]);
|
||||
auto publisher = node->create_publisher<IntraProcessMessage>("/topic");
|
||||
auto publisher = node->create_publisher<IntraProcessMessage>("/topic", 10);
|
||||
|
||||
EXPECT_EQ(publisher->get_subscription_count(), 0u);
|
||||
EXPECT_EQ(publisher->get_intra_process_subscription_count(), 0u);
|
||||
{
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("/topic", &OnMessage);
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("/topic", 10, &OnMessage);
|
||||
rclcpp::sleep_for(offset);
|
||||
EXPECT_EQ(publisher->get_subscription_count(), 1u);
|
||||
EXPECT_EQ(
|
||||
@@ -91,7 +91,7 @@ TEST_P(TestPublisherSubscriptionCount, increasing_and_decreasing_counts)
|
||||
"/ns",
|
||||
parameters.node_options[1]);
|
||||
auto another_sub =
|
||||
another_node->create_subscription<IntraProcessMessage>("/topic", &OnMessage);
|
||||
another_node->create_subscription<IntraProcessMessage>("/topic", 10, &OnMessage);
|
||||
|
||||
rclcpp::sleep_for(offset);
|
||||
EXPECT_EQ(publisher->get_subscription_count(), 2u);
|
||||
|
||||
@@ -56,8 +56,8 @@ TEST(TestSerializedMessageAllocator, borrow_from_subscription) {
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("test_serialized_message_allocator_node");
|
||||
std::shared_ptr<rclcpp::SubscriptionBase> sub =
|
||||
node->create_subscription<test_msgs::msg::Empty>("~/dummy_topic", [](
|
||||
std::shared_ptr<test_msgs::msg::Empty> test_msg) {(void) test_msg;});
|
||||
node->create_subscription<test_msgs::msg::Empty>("~/dummy_topic", 10,
|
||||
[](std::shared_ptr<test_msgs::msg::Empty> test_msg) {(void) test_msg;});
|
||||
|
||||
auto msg0 = sub->create_serialized_message();
|
||||
EXPECT_EQ(0u, msg0->buffer_capacity);
|
||||
|
||||
@@ -95,7 +95,7 @@ public:
|
||||
auto callback = std::bind(
|
||||
&SubscriptionClassNodeInheritance::OnMessage, this, std::placeholders::_1);
|
||||
using rcl_interfaces::msg::IntraProcessMessage;
|
||||
auto sub = this->create_subscription<IntraProcessMessage>("topic", callback);
|
||||
auto sub = this->create_subscription<IntraProcessMessage>("topic", 10, callback);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -112,7 +112,7 @@ public:
|
||||
auto node = std::make_shared<rclcpp::Node>("test_subscription_member_callback", "/ns");
|
||||
auto callback = std::bind(&SubscriptionClass::OnMessage, this, std::placeholders::_1);
|
||||
using rcl_interfaces::msg::IntraProcessMessage;
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("topic", callback);
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("topic", 10, callback);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -125,12 +125,12 @@ TEST_F(TestSubscription, construction_and_destruction) {
|
||||
(void)msg;
|
||||
};
|
||||
{
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("topic", callback);
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("topic", 10, callback);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("invalid_topic?", callback);
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("invalid_topic?", 10, callback);
|
||||
}, rclcpp::exceptions::InvalidTopicNameError);
|
||||
}
|
||||
}
|
||||
@@ -144,17 +144,17 @@ TEST_F(TestSubscriptionSub, construction_and_destruction) {
|
||||
(void)msg;
|
||||
};
|
||||
{
|
||||
auto sub = subnode->create_subscription<IntraProcessMessage>("topic", callback);
|
||||
auto sub = subnode->create_subscription<IntraProcessMessage>("topic", 1, callback);
|
||||
EXPECT_STREQ(sub->get_topic_name(), "/ns/sub_ns/topic");
|
||||
}
|
||||
|
||||
{
|
||||
auto sub = subnode->create_subscription<IntraProcessMessage>("/topic", callback);
|
||||
auto sub = subnode->create_subscription<IntraProcessMessage>("/topic", 1, callback);
|
||||
EXPECT_STREQ(sub->get_topic_name(), "/topic");
|
||||
}
|
||||
|
||||
{
|
||||
auto sub = subnode->create_subscription<IntraProcessMessage>("~/topic", callback);
|
||||
auto sub = subnode->create_subscription<IntraProcessMessage>("~/topic", 1, callback);
|
||||
std::string expected_topic_name =
|
||||
std::string(node->get_namespace()) + "/" + node->get_name() + "/topic";
|
||||
EXPECT_STREQ(sub->get_topic_name(), expected_topic_name.c_str());
|
||||
@@ -162,11 +162,81 @@ TEST_F(TestSubscriptionSub, construction_and_destruction) {
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("invalid_topic?", callback);
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("invalid_topic?", 1, callback);
|
||||
}, rclcpp::exceptions::InvalidTopicNameError);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Testing subscription creation signatures.
|
||||
*/
|
||||
TEST_F(TestSubscription, various_creation_signatures) {
|
||||
using rcl_interfaces::msg::IntraProcessMessage;
|
||||
auto cb = [](rcl_interfaces::msg::IntraProcessMessage::SharedPtr) {};
|
||||
{
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("topic", 1, cb);
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("topic", rclcpp::QoS(1), cb);
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub =
|
||||
node->create_subscription<IntraProcessMessage>("topic", rclcpp::QoS(rclcpp::KeepLast(1)), cb);
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub =
|
||||
node->create_subscription<IntraProcessMessage>("topic", rclcpp::QoS(rclcpp::KeepAll()), cb);
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub = node->create_subscription<IntraProcessMessage>(
|
||||
"topic", 42, cb, rclcpp::SubscriptionOptions());
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub = rclcpp::create_subscription<IntraProcessMessage>(
|
||||
node, "topic", 42, cb, rclcpp::SubscriptionOptions());
|
||||
(void)sub;
|
||||
}
|
||||
// Now deprecated functions.
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
{
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("topic", cb, 42);
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("topic", cb);
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("topic", cb, rmw_qos_profile_default);
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub =
|
||||
node->create_subscription<IntraProcessMessage>("topic", cb, rmw_qos_profile_default, nullptr);
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("topic", cb, 42, nullptr);
|
||||
(void)sub;
|
||||
}
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic pop
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
Testing subscriptions using std::bind.
|
||||
*/
|
||||
@@ -187,6 +257,6 @@ TEST_F(TestSubscription, callback_bind) {
|
||||
// Regression test for https://github.com/ros2/rclcpp/issues/479 where the TEST_F GTest macro
|
||||
// was interfering with rclcpp's `function_traits`.
|
||||
auto callback = std::bind(&TestSubscription::OnMessage, this, std::placeholders::_1);
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("topic", callback);
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("topic", 1, callback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,11 +65,11 @@ TEST_P(TestSubscriptionPublisherCount, increasing_and_decreasing_counts)
|
||||
"my_node",
|
||||
"/ns",
|
||||
node_options);
|
||||
auto subscription = node->create_subscription<IntraProcessMessage>("/topic", &OnMessage);
|
||||
auto subscription = node->create_subscription<IntraProcessMessage>("/topic", 10, &OnMessage);
|
||||
|
||||
EXPECT_EQ(subscription->get_publisher_count(), 0u);
|
||||
{
|
||||
auto pub = node->create_publisher<IntraProcessMessage>("/topic");
|
||||
auto pub = node->create_publisher<IntraProcessMessage>("/topic", 10);
|
||||
rclcpp::sleep_for(offset);
|
||||
EXPECT_EQ(subscription->get_publisher_count(), 1u);
|
||||
{
|
||||
@@ -78,7 +78,7 @@ TEST_P(TestSubscriptionPublisherCount, increasing_and_decreasing_counts)
|
||||
"/ns",
|
||||
node_options);
|
||||
auto another_pub =
|
||||
another_node->create_publisher<IntraProcessMessage>("/topic");
|
||||
another_node->create_publisher<IntraProcessMessage>("/topic", 10);
|
||||
|
||||
rclcpp::sleep_for(offset);
|
||||
EXPECT_EQ(subscription->get_publisher_count(), 2u);
|
||||
|
||||
@@ -45,7 +45,7 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
TEST(TestTime, clock_type_access) {
|
||||
TEST_F(TestTime, clock_type_access) {
|
||||
rclcpp::Clock ros_clock(RCL_ROS_TIME);
|
||||
EXPECT_EQ(RCL_ROS_TIME, ros_clock.get_clock_type());
|
||||
|
||||
@@ -56,7 +56,7 @@ TEST(TestTime, clock_type_access) {
|
||||
EXPECT_EQ(RCL_STEADY_TIME, steady_clock.get_clock_type());
|
||||
}
|
||||
|
||||
TEST(TestTime, time_sources) {
|
||||
TEST_F(TestTime, time_sources) {
|
||||
using builtin_interfaces::msg::Time;
|
||||
rclcpp::Clock ros_clock(RCL_ROS_TIME);
|
||||
Time ros_now = ros_clock.now();
|
||||
@@ -74,42 +74,124 @@ TEST(TestTime, time_sources) {
|
||||
EXPECT_NE(0u, steady_now.nanosec);
|
||||
}
|
||||
|
||||
TEST(TestTime, conversions) {
|
||||
static const int64_t HALF_SEC_IN_NS = 500 * 1000 * 1000;
|
||||
static const int64_t ONE_SEC_IN_NS = 1000 * 1000 * 1000;
|
||||
static const int64_t ONE_AND_HALF_SEC_IN_NS = 3 * HALF_SEC_IN_NS;
|
||||
|
||||
TEST_F(TestTime, conversions) {
|
||||
rclcpp::Clock system_clock(RCL_SYSTEM_TIME);
|
||||
|
||||
rclcpp::Time now = system_clock.now();
|
||||
builtin_interfaces::msg::Time now_msg = now;
|
||||
{
|
||||
rclcpp::Time now = system_clock.now();
|
||||
builtin_interfaces::msg::Time now_msg = now;
|
||||
|
||||
rclcpp::Time now_again = now_msg;
|
||||
EXPECT_EQ(now.nanoseconds(), now_again.nanoseconds());
|
||||
rclcpp::Time now_again = now_msg;
|
||||
EXPECT_EQ(now.nanoseconds(), now_again.nanoseconds());
|
||||
}
|
||||
|
||||
builtin_interfaces::msg::Time msg;
|
||||
msg.sec = 12345;
|
||||
msg.nanosec = 67890;
|
||||
{
|
||||
rclcpp::Time positive_time = rclcpp::Time(12345, 67890u);
|
||||
|
||||
rclcpp::Time time = msg;
|
||||
EXPECT_EQ(
|
||||
RCL_S_TO_NS(static_cast<int64_t>(msg.sec)) + static_cast<int64_t>(msg.nanosec),
|
||||
time.nanoseconds());
|
||||
EXPECT_EQ(static_cast<int64_t>(msg.sec), RCL_NS_TO_S(time.nanoseconds()));
|
||||
builtin_interfaces::msg::Time msg = positive_time;
|
||||
EXPECT_EQ(msg.sec, 12345);
|
||||
EXPECT_EQ(msg.nanosec, 67890u);
|
||||
|
||||
builtin_interfaces::msg::Time negative_time_msg;
|
||||
negative_time_msg.sec = -1;
|
||||
negative_time_msg.nanosec = 1;
|
||||
rclcpp::Time time = msg;
|
||||
EXPECT_EQ(time.nanoseconds(), positive_time.nanoseconds());
|
||||
EXPECT_EQ(
|
||||
RCL_S_TO_NS(static_cast<int64_t>(msg.sec)) + static_cast<int64_t>(msg.nanosec),
|
||||
time.nanoseconds());
|
||||
EXPECT_EQ(static_cast<int64_t>(msg.sec), RCL_NS_TO_S(time.nanoseconds()));
|
||||
}
|
||||
|
||||
EXPECT_ANY_THROW({
|
||||
rclcpp::Time negative_time = negative_time_msg;
|
||||
});
|
||||
// throw on construction/assignment of negative times
|
||||
{
|
||||
builtin_interfaces::msg::Time negative_time_msg;
|
||||
negative_time_msg.sec = -1;
|
||||
negative_time_msg.nanosec = 1;
|
||||
|
||||
EXPECT_ANY_THROW(rclcpp::Time(-1, 1));
|
||||
EXPECT_ANY_THROW(
|
||||
{
|
||||
rclcpp::Time negative_time = negative_time_msg;
|
||||
});
|
||||
|
||||
EXPECT_ANY_THROW({
|
||||
rclcpp::Time assignment(1, 2);
|
||||
assignment = negative_time_msg;
|
||||
});
|
||||
EXPECT_ANY_THROW(rclcpp::Time(-1, 1));
|
||||
|
||||
EXPECT_ANY_THROW(
|
||||
{
|
||||
rclcpp::Time assignment(1, 2);
|
||||
assignment = negative_time_msg;
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
const rclcpp::Time time(HALF_SEC_IN_NS);
|
||||
const auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
|
||||
EXPECT_EQ(time_msg.sec, 0);
|
||||
EXPECT_EQ(time_msg.nanosec, HALF_SEC_IN_NS);
|
||||
EXPECT_EQ(rclcpp::Time(time_msg).nanoseconds(), HALF_SEC_IN_NS);
|
||||
}
|
||||
|
||||
{
|
||||
const rclcpp::Time time(ONE_SEC_IN_NS);
|
||||
const auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
|
||||
EXPECT_EQ(time_msg.sec, 1);
|
||||
EXPECT_EQ(time_msg.nanosec, 0u);
|
||||
EXPECT_EQ(rclcpp::Time(time_msg).nanoseconds(), ONE_SEC_IN_NS);
|
||||
}
|
||||
|
||||
{
|
||||
const rclcpp::Time time(ONE_AND_HALF_SEC_IN_NS);
|
||||
auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
|
||||
EXPECT_EQ(time_msg.sec, 1);
|
||||
EXPECT_EQ(time_msg.nanosec, HALF_SEC_IN_NS);
|
||||
EXPECT_EQ(rclcpp::Time(time_msg).nanoseconds(), ONE_AND_HALF_SEC_IN_NS);
|
||||
}
|
||||
|
||||
{
|
||||
// Can rclcpp::Time be negative or not? The following constructor works:
|
||||
rclcpp::Time time(-HALF_SEC_IN_NS);
|
||||
auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
|
||||
EXPECT_EQ(time_msg.sec, -1);
|
||||
EXPECT_EQ(time_msg.nanosec, HALF_SEC_IN_NS);
|
||||
|
||||
// The opposite conversion throws...
|
||||
EXPECT_ANY_THROW(
|
||||
{
|
||||
rclcpp::Time negative_time(time_msg);
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
// Can rclcpp::Time be negative or not? The following constructor works:
|
||||
rclcpp::Time time(-ONE_SEC_IN_NS);
|
||||
auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
|
||||
EXPECT_EQ(time_msg.sec, -1);
|
||||
EXPECT_EQ(time_msg.nanosec, 0u);
|
||||
|
||||
// The opposite conversion throws...
|
||||
EXPECT_ANY_THROW(
|
||||
{
|
||||
rclcpp::Time negative_time(time_msg);
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
// Can rclcpp::Time be negative or not? The following constructor works:
|
||||
rclcpp::Time time(-ONE_AND_HALF_SEC_IN_NS);
|
||||
auto time_msg = static_cast<builtin_interfaces::msg::Time>(time);
|
||||
EXPECT_EQ(time_msg.sec, -2);
|
||||
EXPECT_EQ(time_msg.nanosec, HALF_SEC_IN_NS);
|
||||
|
||||
// The opposite conversion throws...
|
||||
EXPECT_ANY_THROW(
|
||||
{
|
||||
rclcpp::Time negative_time(time_msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestTime, operators) {
|
||||
TEST_F(TestTime, operators) {
|
||||
rclcpp::Time old(1, 0);
|
||||
rclcpp::Time young(2, 0);
|
||||
|
||||
@@ -121,7 +203,7 @@ TEST(TestTime, operators) {
|
||||
EXPECT_TRUE(young != old);
|
||||
|
||||
rclcpp::Duration sub = young - old;
|
||||
EXPECT_EQ(sub.nanoseconds(), (rcl_duration_value_t)(young.nanoseconds() - old.nanoseconds()));
|
||||
EXPECT_EQ(sub.nanoseconds(), (young.nanoseconds() - old.nanoseconds()));
|
||||
EXPECT_EQ(sub, young - old);
|
||||
|
||||
rclcpp::Time system_time(0, 0, RCL_SYSTEM_TIME);
|
||||
@@ -160,7 +242,7 @@ TEST(TestTime, operators) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestTime, overflow_detectors) {
|
||||
TEST_F(TestTime, overflow_detectors) {
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Test logical_eq call first:
|
||||
EXPECT_TRUE(logical_eq(false, false));
|
||||
@@ -180,8 +262,8 @@ TEST(TestTime, overflow_detectors) {
|
||||
// 256 * 256 = 64K total loops, should be pretty fast on everything
|
||||
for (big_type_t y = min_val; y <= max_val; ++y) {
|
||||
for (big_type_t x = min_val; x <= max_val; ++x) {
|
||||
const big_type_t sum = x + y;
|
||||
const big_type_t diff = x - y;
|
||||
const big_type_t sum = static_cast<big_type_t>(x + y);
|
||||
const big_type_t diff = static_cast<big_type_t>(x - y);
|
||||
|
||||
const bool add_will_overflow =
|
||||
rclcpp::add_will_overflow(test_type_t(x), test_type_t(y));
|
||||
@@ -217,7 +299,7 @@ TEST(TestTime, overflow_detectors) {
|
||||
EXPECT_TRUE(rclcpp::sub_will_underflow<int64_t>(INT64_MIN, 1));
|
||||
}
|
||||
|
||||
TEST(TestTime, overflows) {
|
||||
TEST_F(TestTime, overflows) {
|
||||
rclcpp::Time max_time(std::numeric_limits<rcl_time_point_value_t>::max());
|
||||
rclcpp::Time min_time(std::numeric_limits<rcl_time_point_value_t>::min());
|
||||
rclcpp::Duration one(1);
|
||||
@@ -245,7 +327,7 @@ TEST(TestTime, overflows) {
|
||||
EXPECT_NO_THROW(one_time - two_time);
|
||||
}
|
||||
|
||||
TEST(TestTime, seconds) {
|
||||
TEST_F(TestTime, seconds) {
|
||||
EXPECT_DOUBLE_EQ(0.0, rclcpp::Time(0, 0).seconds());
|
||||
EXPECT_DOUBLE_EQ(4.5, rclcpp::Time(4, 500000000).seconds());
|
||||
EXPECT_DOUBLE_EQ(2.5, rclcpp::Time(0, 2500000000).seconds());
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user