Compare commits
97 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 | ||
|
|
d34fa607a2 | ||
|
|
02050c3901 | ||
|
|
1a0f8e3f28 | ||
|
|
0da966b981 | ||
|
|
6b10841477 | ||
|
|
97ed34a042 | ||
|
|
ddf4d345b3 | ||
|
|
ddcc1ec553 | ||
|
|
60996d1e59 | ||
|
|
713dd0c184 | ||
|
|
68d0ac1e61 | ||
|
|
70f48d68b9 | ||
|
|
fcfe94e404 |
@@ -2,6 +2,134 @@
|
||||
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>`_)
|
||||
* Fixed a concurrency problem in the multithreaded executor. (`#703 <https://github.com/ros2/rclcpp/issues/703>`_)
|
||||
* Fixup utilities. (`#692 <https://github.com/ros2/rclcpp/issues/692>`_)
|
||||
* Added method to read timer cancellation. (`#697 <https://github.com/ros2/rclcpp/issues/697>`_)
|
||||
* Added Exception Generator function for implementing "from_rcl_error". (`#678 <https://github.com/ros2/rclcpp/issues/678>`_)
|
||||
* Updated initialization of rmw_qos_profile_t struct instances. (`#691 <https://github.com/ros2/rclcpp/issues/691>`_)
|
||||
* Removed the const value from the logger before comparison. (`#680 <https://github.com/ros2/rclcpp/issues/680>`_)
|
||||
* Contributors: Devin Bonnie, Dima Dorezyuk, Guillaume Autran, M. M, Shane Loretz, Víctor Mayoral Vilches, William Woodall, jhdcs
|
||||
|
||||
0.7.0 (2019-04-14)
|
||||
------------------
|
||||
* Added Options-struct interfaces for creating publishers/subscribers (pre-QoS, standalone). (`#673 <https://github.com/ros2/rclcpp/issues/673>`_)
|
||||
|
||||
@@ -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,9 +258,12 @@ if(BUILD_TESTING)
|
||||
)
|
||||
target_link_libraries(test_node_global_args ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_node_initial_parameters test/test_node_initial_parameters.cpp)
|
||||
if(TARGET test_node_initial_parameters)
|
||||
target_link_libraries(test_node_initial_parameters ${PROJECT_NAME})
|
||||
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)
|
||||
@@ -248,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
|
||||
@@ -397,6 +439,14 @@ if(BUILD_TESTING)
|
||||
target_link_libraries(test_time ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_timer test/test_timer.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
if(TARGET test_timer)
|
||||
ament_target_dependencies(test_timer
|
||||
"rcl")
|
||||
target_link_libraries(test_timer ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_time_source test/test_time_source.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
if(TARGET test_time_source)
|
||||
|
||||
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
|
||||
{
|
||||
@@ -185,14 +187,35 @@ public:
|
||||
class InvalidParametersException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
// Inherit constructors from runtime_error;
|
||||
// Inherit constructors from runtime_error.
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
/// Throwing if passed parameter value is invalid.
|
||||
/// Thrown if passed parameter value is invalid.
|
||||
class InvalidParameterValueException : public std::runtime_error
|
||||
{
|
||||
// Inherit constructors from runtime_error;
|
||||
// Inherit constructors from runtime_error.
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
/// Thrown if parameter is already declared.
|
||||
class ParameterAlreadyDeclaredException : public std::runtime_error
|
||||
{
|
||||
// Inherit constructors from runtime_error.
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
/// Thrown if parameter is not declared, e.g. either set or get was called without first declaring.
|
||||
class ParameterNotDeclaredException : public std::runtime_error
|
||||
{
|
||||
// Inherit constructors from runtime_error.
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
/// Thrown if parameter is immutable and therefore cannot be undeclared.
|
||||
class ParameterImmutableException : public std::runtime_error
|
||||
{
|
||||
// Inherit constructors from runtime_error.
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
@@ -41,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"
|
||||
@@ -52,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"
|
||||
@@ -143,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.
|
||||
*/
|
||||
@@ -155,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.
|
||||
/**
|
||||
@@ -188,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.
|
||||
/**
|
||||
@@ -219,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
|
||||
@@ -249,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,
|
||||
@@ -259,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.
|
||||
/**
|
||||
@@ -283,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.
|
||||
/**
|
||||
@@ -312,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(
|
||||
@@ -320,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(
|
||||
@@ -329,96 +367,438 @@ public:
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
/// Declare and initialize a parameter, return the effective value.
|
||||
/**
|
||||
* This method is used to declare that a parameter exists on this node.
|
||||
* If, at run-time, the user has provided an initial value then it will be
|
||||
* set in this method, otherwise the given default_value will be set.
|
||||
* In either case, the resulting value is returned, whether or not it is
|
||||
* based on the default value or the user provided initial value.
|
||||
*
|
||||
* If no parameter_descriptor is given, then the default values from the
|
||||
* message definition will be used, e.g. read_only will be false.
|
||||
*
|
||||
* The name and type in the given rcl_interfaces::msg::ParameterDescriptor
|
||||
* are ignored, and should be specified using the name argument to this
|
||||
* function and the default value's type instead.
|
||||
*
|
||||
* This method, if successful, will result in any callback registered with
|
||||
* set_on_parameters_set_callback to be called.
|
||||
* If that callback prevents the initial value for the parameter from being
|
||||
* set then rclcpp::exceptions::InvalidParameterValueException is thrown.
|
||||
*
|
||||
* The returned reference will remain valid until the parameter is
|
||||
* undeclared.
|
||||
*
|
||||
* \param[in] name The name of the parameter.
|
||||
* \param[in] default_value An initial value to be used if at run-time user
|
||||
* did not override it.
|
||||
* \param[in] parameter_descriptor An optional, custom description for
|
||||
* the parameter.
|
||||
* \return A const reference to the value of the parameter.
|
||||
* \throws rclcpp::exceptions::ParameterAlreadyDeclaredException if parameter
|
||||
* has already been declared.
|
||||
* \throws rclcpp::exceptions::InvalidParametersException if a parameter
|
||||
* name is invalid.
|
||||
* \throws rclcpp::exceptions::InvalidParameterValueException if initial
|
||||
* value fails to be set.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
const rclcpp::ParameterValue &
|
||||
declare_parameter(
|
||||
const std::string & name,
|
||||
const rclcpp::ParameterValue & default_value = rclcpp::ParameterValue(),
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
|
||||
rcl_interfaces::msg::ParameterDescriptor());
|
||||
|
||||
/// Declare and initialize a parameter with a type.
|
||||
/**
|
||||
* See the non-templated declare_parameter() on this class for details.
|
||||
*
|
||||
* If the type of the default value, and therefore also the type of return
|
||||
* value, differs from the initial value provided in the node options, then
|
||||
* a rclcpp::ParameterTypeException may be thrown.
|
||||
* To avoid this, use the declare_parameter() method which returns an
|
||||
* rclcpp::ParameterValue instead.
|
||||
*
|
||||
* Note, this method cannot return a const reference, because extending the
|
||||
* lifetime of a temporary only works recursively with member initializers,
|
||||
* and cannot be extended to members of a class returned.
|
||||
* The return value of this class is a copy of the member of a ParameterValue
|
||||
* which is returned by the other version of declare_parameter().
|
||||
* See also:
|
||||
*
|
||||
* - https://en.cppreference.com/w/cpp/language/lifetime
|
||||
* - https://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
|
||||
* - https://www.youtube.com/watch?v=uQyT-5iWUow (cppnow 2018 presentation)
|
||||
*/
|
||||
template<typename ParameterT>
|
||||
auto
|
||||
declare_parameter(
|
||||
const std::string & name,
|
||||
const ParameterT & default_value,
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
|
||||
rcl_interfaces::msg::ParameterDescriptor());
|
||||
|
||||
/// Declare and initialize several parameters with the same namespace and type.
|
||||
/**
|
||||
* For each key in the map, a parameter with a name of "namespace.key"
|
||||
* will be set to the value in the map.
|
||||
* The resulting value for each declared parameter will be returned.
|
||||
*
|
||||
* The name expansion is naive, so if you set the namespace to be "foo.",
|
||||
* then the resulting parameter names will be like "foo..key".
|
||||
* However, if the namespace is an empty string, then no leading '.' will be
|
||||
* placed before each key, which would have been the case when naively
|
||||
* expanding "namespace.key".
|
||||
* This allows you to declare several parameters at once without a namespace.
|
||||
*
|
||||
* The map may either contain default values for parameters, or a std::pair
|
||||
* where the first element is a default value and the second is a
|
||||
* parameter descriptor.
|
||||
* This function only takes the default value, but there is another overload
|
||||
* which takes the std::pair with the default value and descriptor.
|
||||
*
|
||||
* This method, if successful, will result in any callback registered with
|
||||
* set_on_parameters_set_callback to be called, once for each parameter.
|
||||
* If that callback prevents the initial value for any parameter from being
|
||||
* set then rclcpp::exceptions::InvalidParameterValueException is thrown.
|
||||
*
|
||||
* \param[in] namespace_ The namespace in which to declare the parameters.
|
||||
* \param[in] parameters The parameters to set in the given namespace.
|
||||
* \throws rclcpp::exceptions::ParameterAlreadyDeclaredException if parameter
|
||||
* has already been declared.
|
||||
* \throws rclcpp::exceptions::InvalidParametersException if a parameter
|
||||
* name is invalid.
|
||||
* \throws rclcpp::exceptions::InvalidParameterValueException if initial
|
||||
* value fails to be set.
|
||||
*/
|
||||
template<typename ParameterT>
|
||||
std::vector<ParameterT>
|
||||
declare_parameters(
|
||||
const std::string & namespace_,
|
||||
const std::map<std::string, ParameterT> & parameters);
|
||||
|
||||
/// Declare and initialize several parameters with the same namespace and type.
|
||||
/**
|
||||
* This version will take a map where the value is a pair, with the default
|
||||
* parameter value as the first item and a parameter descriptor as the second.
|
||||
*
|
||||
* See the simpler declare_parameters() on this class for more details.
|
||||
*/
|
||||
template<typename ParameterT>
|
||||
std::vector<ParameterT>
|
||||
declare_parameters(
|
||||
const std::string & namespace_,
|
||||
const std::map<
|
||||
std::string,
|
||||
std::pair<ParameterT, rcl_interfaces::msg::ParameterDescriptor>
|
||||
> & parameters);
|
||||
|
||||
/// Undeclare a previously declared parameter.
|
||||
/**
|
||||
* This method will not cause a callback registered with
|
||||
* set_on_parameters_set_callback to be called.
|
||||
*
|
||||
* \param[in] name The name of the parameter to be undeclared.
|
||||
* \throws rclcpp::exceptions::ParameterNotDeclaredException if the parameter
|
||||
* has not been declared.
|
||||
* \throws rclcpp::exceptions::ParameterImmutableException if the parameter
|
||||
* was create as read_only (immutable).
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
undeclare_parameter(const std::string & name);
|
||||
|
||||
/// Return true if a given parameter is declared.
|
||||
/**
|
||||
* \param[in] name The name of the parameter to check for being declared.
|
||||
* \return true if the parameter name has been declared, otherwise false.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
has_parameter(const std::string & name) const;
|
||||
|
||||
/// Set a single parameter.
|
||||
/**
|
||||
* Set the given parameter and then return result of the set action.
|
||||
*
|
||||
* If the parameter has not been declared this function may throw the
|
||||
* rclcpp::exceptions::ParameterNotDeclaredException exception, but only if
|
||||
* the node was not created with the
|
||||
* 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.
|
||||
* If the callback prevents the parameter from being set, then it will be
|
||||
* reflected in the SetParametersResult that is returned, but no exception
|
||||
* will be thrown.
|
||||
*
|
||||
* If the value type of the parameter is rclcpp::PARAMETER_NOT_SET, and the
|
||||
* existing parameter type is something else, then the parameter will be
|
||||
* implicitly undeclared.
|
||||
* This will result in a parameter event indicating that the parameter was
|
||||
* deleted.
|
||||
*
|
||||
* \param[in] parameter The parameter to be set.
|
||||
* \return The result of the set action.
|
||||
* \throws rclcpp::exceptions::ParameterNotDeclaredException if the parameter
|
||||
* has not been declared and undeclared parameters are not allowed.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
set_parameter(const rclcpp::Parameter & parameter);
|
||||
|
||||
/// Set one or more parameters, one at a time.
|
||||
/**
|
||||
* Set the given parameters, one at a time, and then return result of each
|
||||
* set action.
|
||||
*
|
||||
* Parameters are set in the order they are given within the input vector.
|
||||
*
|
||||
* Like set_parameter, if any of the parameters to be set have not first been
|
||||
* declared, and undeclared parameters are not allowed (the default), then
|
||||
* this method will throw rclcpp::exceptions::ParameterNotDeclaredException.
|
||||
*
|
||||
* If setting a parameter fails due to not being declared, then the
|
||||
* parameters which have already been set will stay set, and no attempt will
|
||||
* be made to set the parameters which come after.
|
||||
*
|
||||
* If a parameter fails to be set due to any other reason, like being
|
||||
* rejected by the user's callback (basically any reason other than not
|
||||
* having been declared beforehand), then that is reflected in the
|
||||
* corresponding SetParametersResult in the vector returned by this function.
|
||||
*
|
||||
* This method will result in any callback registered with
|
||||
* set_on_parameters_set_callback to be called, once for each parameter.
|
||||
* If the callback prevents the parameter from being set, then, as mentioned
|
||||
* before, it will be reflected in the corresponding SetParametersResult
|
||||
* that is returned, but no exception will be thrown.
|
||||
*
|
||||
* Like set_parameter() this method will implicitly undeclare parameters
|
||||
* with the type rclcpp::PARAMETER_NOT_SET.
|
||||
*
|
||||
* \param[in] parameters The vector of parameters to be set.
|
||||
* \return The results for each set action as a vector.
|
||||
* \throws rclcpp::exceptions::ParameterNotDeclaredException if any parameter
|
||||
* has not been declared and undeclared parameters are not allowed.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
set_parameters(const std::vector<rclcpp::Parameter> & parameters);
|
||||
|
||||
/// Set one or more parameters, all at once.
|
||||
/**
|
||||
* Set the given parameters, all at one time, and then aggregate result.
|
||||
*
|
||||
* Behaves like set_parameter, except that it sets multiple parameters,
|
||||
* failing all if just one of the parameters are unsuccessfully set.
|
||||
* Either all of the parameters are set or none of them are set.
|
||||
*
|
||||
* Like set_parameter and set_parameters, this method may throw an
|
||||
* rclcpp::exceptions::ParameterNotDeclaredException exception if any of the
|
||||
* parameters to be set have not first been declared.
|
||||
* If the exception is thrown then none of the parameters will have been set.
|
||||
*
|
||||
* This method will result in any callback registered with
|
||||
* set_on_parameters_set_callback to be called, just one time.
|
||||
* If the callback prevents the parameters from being set, then it will be
|
||||
* reflected in the SetParametersResult which is returned, but no exception
|
||||
* will be thrown.
|
||||
*
|
||||
* If you pass multiple rclcpp::Parameter instances with the same name, then
|
||||
* only the last one in the vector (forward iteration) will be set.
|
||||
*
|
||||
* Like set_parameter() this method will implicitly undeclare parameters
|
||||
* with the type rclcpp::PARAMETER_NOT_SET.
|
||||
*
|
||||
* \param[in] parameters The vector of parameters to be set.
|
||||
* \return The aggregate result of setting all the parameters atomically.
|
||||
* \throws rclcpp::exceptions::ParameterNotDeclaredException if any parameter
|
||||
* has not been declared and undeclared parameters are not allowed.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
set_parameters_atomically(const std::vector<rclcpp::Parameter> & parameters);
|
||||
|
||||
/// Set one parameter, unless that parameter has already been set.
|
||||
/**
|
||||
* Set the given parameter unless already set.
|
||||
*
|
||||
* Deprecated, instead use declare_parameter().
|
||||
*
|
||||
* \param[in] parameters The vector of parameters to be set.
|
||||
* \return The result of each set action as a vector.
|
||||
*/
|
||||
template<typename ParameterT>
|
||||
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
|
||||
[[deprecated("use declare_parameter() instead")]]
|
||||
void
|
||||
set_parameter_if_not_set(
|
||||
const std::string & name,
|
||||
const ParameterT & value);
|
||||
set_parameter_if_not_set(const std::string & name, const ParameterT & value);
|
||||
|
||||
/// Set a map of parameters with the same prefix.
|
||||
/**
|
||||
* For each key in the map, a parameter with a name of "name.key" will be set
|
||||
* to the value in the map.
|
||||
*
|
||||
* Deprecated, instead use declare_parameters().
|
||||
*
|
||||
* \param[in] name The prefix of the parameters to set.
|
||||
* \param[in] values The parameters to set in the given prefix.
|
||||
*/
|
||||
template<typename MapValueT>
|
||||
template<typename ParameterT>
|
||||
[[deprecated("use declare_parameters() instead")]]
|
||||
void
|
||||
set_parameters_if_not_set(
|
||||
const std::string & name,
|
||||
const std::map<std::string, MapValueT> & values);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rclcpp::Parameter>
|
||||
get_parameters(const std::vector<std::string> & names) const;
|
||||
const std::map<std::string, ParameterT> & values);
|
||||
|
||||
/// Return the parameter by the given name.
|
||||
/**
|
||||
* If the parameter has not been declared, then this method may throw the
|
||||
* rclcpp::exceptions::ParameterNotDeclaredException exception.
|
||||
*
|
||||
* If undeclared parameters are allowed, see the node option
|
||||
* rclcpp::NodeOptions::allow_undeclared_parameters, then this method will
|
||||
* not throw an exception, and instead return a default initialized
|
||||
* rclcpp::Parameter, which has a type of
|
||||
* rclcpp::ParameterType::PARAMETER_NOT_SET.
|
||||
*
|
||||
* \param[in] name The name of the parameter to get.
|
||||
* \return The requested parameter inside of a rclcpp parameter object.
|
||||
* \throws rclcpp::exceptions::ParameterNotDeclaredException if the parameter
|
||||
* has not been declared and undeclared parameters are not allowed.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::Parameter
|
||||
get_parameter(const std::string & name) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
get_parameter(
|
||||
const std::string & name,
|
||||
rclcpp::Parameter & parameter) const;
|
||||
|
||||
/// Assign the value of the parameter if set into the parameter argument.
|
||||
/// Get the value of a parameter by the given name, and return true if it was set.
|
||||
/**
|
||||
* If the parameter was not set, then the "parameter" argument is never assigned a value.
|
||||
* This method will never throw the
|
||||
* rclcpp::exceptions::ParameterNotDeclaredException exception, but will
|
||||
* instead return false if the parameter has not be previously declared.
|
||||
*
|
||||
* If the parameter was not declared, then the output argument for this
|
||||
* method which is called "parameter" will not be assigned a value.
|
||||
* If the parameter was declared, and therefore has a value, then it is
|
||||
* assigned into the "parameter" argument of this method.
|
||||
*
|
||||
* \param[in] name The name of the parameter to get.
|
||||
* \param[out] parameter The output where the value of the parameter should be assigned.
|
||||
* \returns true if the parameter was set, false otherwise
|
||||
* \param[out] parameter The output storage for the parameter being retrieved.
|
||||
* \return true if the parameter was previously declared, otherwise false.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
get_parameter(const std::string & name, rclcpp::Parameter & parameter) const;
|
||||
|
||||
/// Get the value of a parameter by the given name, and return true if it was set.
|
||||
/**
|
||||
* Identical to the non-templated version of this method, except that when
|
||||
* assigning the output argument called "parameter", this method will attempt
|
||||
* to coerce the parameter value into the type requested by the given
|
||||
* template argument, which may fail and throw an exception.
|
||||
*
|
||||
* If the parameter has not been declared, it will not attempt to coerce the
|
||||
* value into the requested type, as it is known that the type is not set.
|
||||
*
|
||||
* \throws rclcpp::ParameterTypeException if the requested type does not
|
||||
* match the value of the parameter which is stored.
|
||||
*/
|
||||
template<typename ParameterT>
|
||||
bool
|
||||
get_parameter(const std::string & name, ParameterT & parameter) const;
|
||||
|
||||
/// Assign the value of the map parameter if set into the values argument.
|
||||
/// Get the parameter value, or the "alternative_value" if not set, and assign it to "parameter".
|
||||
/**
|
||||
* Parameter names that are part of a map are of the form "name.member".
|
||||
* This API gets all parameters that begin with "name", storing them into the
|
||||
* map with the name of the parameter and their value.
|
||||
* If there are no members in the named map, then the "values" argument is not changed.
|
||||
*
|
||||
* \param[in] name The prefix of the parameters to get.
|
||||
* \param[out] values The map of output values, with one std::string,MapValueT
|
||||
* per parameter.
|
||||
* \returns true if values was changed, false otherwise
|
||||
*/
|
||||
template<typename MapValueT>
|
||||
bool
|
||||
get_parameters(
|
||||
const std::string & name,
|
||||
std::map<std::string, MapValueT> & values) const;
|
||||
|
||||
/// Get the parameter value, or the "alternative value" if not set, and assign it to "value".
|
||||
/**
|
||||
* If the parameter was not set, then the "value" argument is assigned
|
||||
* If the parameter was not set, then the "parameter" argument is assigned
|
||||
* the "alternative_value".
|
||||
* In all cases, the parameter remains not set after this function is called.
|
||||
*
|
||||
* Like the version of get_parameter() which returns a bool, this method will
|
||||
* not throw the rclcpp::exceptions::ParameterNotDeclaredException exception.
|
||||
*
|
||||
* In all cases, the parameter is never set or declared within the node.
|
||||
*
|
||||
* \param[in] name The name of the parameter to get.
|
||||
* \param[out] value The output where the value of the parameter should be assigned.
|
||||
* \param[out] parameter The output where the value of the parameter should be assigned.
|
||||
* \param[in] alternative_value Value to be stored in output if the parameter was not set.
|
||||
* \returns true if the parameter was set, false otherwise
|
||||
* \returns true if the parameter was set, false otherwise.
|
||||
*/
|
||||
template<typename ParameterT>
|
||||
bool
|
||||
get_parameter_or(
|
||||
const std::string & name,
|
||||
ParameterT & value,
|
||||
ParameterT & parameter,
|
||||
const ParameterT & alternative_value) const;
|
||||
|
||||
/// Return the parameters by the given parameter names.
|
||||
/**
|
||||
* Like get_parameters(), this method may throw the
|
||||
* rclcpp::exceptions::ParameterNotDeclaredException exception if the
|
||||
* requested parameter has not been declared and undeclared parameters are
|
||||
* not allowed.
|
||||
*
|
||||
* Also like get_parameters(), if undeclared parameters are allowed and the
|
||||
* parameter has not been declared, then the corresponding rclcpp::Parameter
|
||||
* will be default initialized and therefore have the type
|
||||
* rclcpp::ParameterType::PARAMETER_NOT_SET.
|
||||
*
|
||||
* \param[in] names The names of the parameters to be retrieved.
|
||||
* \return The parameters that were retrieved.
|
||||
* \throws rclcpp::exceptions::ParameterNotDeclaredException if any of the
|
||||
* parameters have not been declared and undeclared parameters are not
|
||||
* allowed.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rclcpp::Parameter>
|
||||
get_parameters(const std::vector<std::string> & names) const;
|
||||
|
||||
/// Get the parameter values for all parameters that have a given prefix.
|
||||
/**
|
||||
* The "prefix" argument is used to list the parameters which are prefixed
|
||||
* with that prefix, see also list_parameters().
|
||||
*
|
||||
* The resulting list of parameter names are used to get the values of the
|
||||
* parameters.
|
||||
*
|
||||
* The names which are used as keys in the values map have the prefix removed.
|
||||
* For example, if you use the prefix "foo" and the parameters "foo.ping" and
|
||||
* "foo.pong" exist, then the returned map will have the keys "ping" and
|
||||
* "pong".
|
||||
*
|
||||
* An empty string for the prefix will match all parameters.
|
||||
*
|
||||
* If no parameters with the prefix are found, then the output parameter
|
||||
* "values" will be unchanged and false will be returned.
|
||||
* Otherwise, the parameter names and values will be stored in the map and
|
||||
* true will be returned to indicate "values" was mutated.
|
||||
*
|
||||
* This method will never throw the
|
||||
* rclcpp::exceptions::ParameterNotDeclaredException exception because the
|
||||
* action of listing the parameters is done atomically with getting the
|
||||
* values, and therefore they are only listed if already declared and cannot
|
||||
* be undeclared before being retrieved.
|
||||
*
|
||||
* Like the templated get_parameter() variant, this method will attempt to
|
||||
* coerce the parameter values into the type requested by the given
|
||||
* template argument, which may fail and throw an exception.
|
||||
*
|
||||
* \param[in] prefix The prefix of the parameters to get.
|
||||
* \param[out] values The map used to store the parameter names and values,
|
||||
* respectively, with one entry per parameter matching prefix.
|
||||
* \returns true if output "values" was changed, false otherwise.
|
||||
* \throws rclcpp::ParameterTypeException if the requested type does not
|
||||
* match the value of the parameter which is stored.
|
||||
*/
|
||||
template<typename ParameterT>
|
||||
bool
|
||||
get_parameters(
|
||||
const std::string & prefix,
|
||||
std::map<std::string, ParameterT> & values) const;
|
||||
|
||||
/// Get the parameter value; if not set, set the "alternative value" and store it in the node.
|
||||
/**
|
||||
* If the parameter is set, then the "value" argument is assigned the value
|
||||
@@ -426,39 +806,159 @@ public:
|
||||
* If the parameter is not set, then the "value" argument is assigned the "alternative_value",
|
||||
* and the parameter is set to the "alternative_value" on the node.
|
||||
*
|
||||
* Deprecated, instead use declare_parameter()'s return value, or use
|
||||
* has_parameter() to ensure it exists before getting it.
|
||||
*
|
||||
* \param[in] name The name of the parameter to get.
|
||||
* \param[out] value The output where the value of the parameter should be assigned.
|
||||
* \param[in] alternative_value Value to be stored in output and parameter if the parameter was not set.
|
||||
* \param[in] alternative_value Value to be used if the parameter was not set.
|
||||
*/
|
||||
template<typename ParameterT>
|
||||
[[deprecated("use declare_parameter() and it's return value instead")]]
|
||||
void
|
||||
get_parameter_or_set(
|
||||
const std::string & name,
|
||||
ParameterT & value,
|
||||
const ParameterT & alternative_value);
|
||||
|
||||
/// Return the parameter descriptor for the given parameter name.
|
||||
/**
|
||||
* Like get_parameters(), this method may throw the
|
||||
* rclcpp::exceptions::ParameterNotDeclaredException exception if the
|
||||
* requested parameter has not been declared and undeclared parameters are
|
||||
* not allowed.
|
||||
*
|
||||
* If undeclared parameters are allowed, then a default initialized
|
||||
* descriptor will be returned.
|
||||
*
|
||||
* \param[in] name The name of the parameter to describe.
|
||||
* \return The descriptor for the given parameter name.
|
||||
* \throws rclcpp::exceptions::ParameterNotDeclaredException if the
|
||||
* parameter has not been declared and undeclared parameters are not
|
||||
* allowed.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rcl_interfaces::msg::ParameterDescriptor
|
||||
describe_parameter(const std::string & name) const;
|
||||
|
||||
/// Return a vector of parameter descriptors, one for each of the given names.
|
||||
/**
|
||||
* Like get_parameters(), this method may throw the
|
||||
* rclcpp::exceptions::ParameterNotDeclaredException exception if any of the
|
||||
* requested parameters have not been declared and undeclared parameters are
|
||||
* not allowed.
|
||||
*
|
||||
* If undeclared parameters are allowed, then a default initialized
|
||||
* descriptor will be returned for the undeclared parameter's descriptor.
|
||||
*
|
||||
* If the names vector is empty, then an empty vector will be returned.
|
||||
*
|
||||
* \param[in] names The list of parameter names to describe.
|
||||
* \return A list of parameter descriptors, one for each parameter given.
|
||||
* \throws rclcpp::exceptions::ParameterNotDeclaredException if any of the
|
||||
* parameters have not been declared and undeclared parameters are not
|
||||
* allowed.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rcl_interfaces::msg::ParameterDescriptor>
|
||||
describe_parameters(const std::vector<std::string> & names) const;
|
||||
|
||||
/// Return a vector of parameter types, one for each of the given names.
|
||||
/**
|
||||
* Like get_parameters(), this method may throw the
|
||||
* rclcpp::exceptions::ParameterNotDeclaredException exception if any of the
|
||||
* requested parameters have not been declared and undeclared parameters are
|
||||
* not allowed.
|
||||
*
|
||||
* If undeclared parameters are allowed, then the default type
|
||||
* rclcpp::ParameterType::PARAMETER_NOT_SET will be returned.
|
||||
*
|
||||
* \param[in] names The list of parameter names to get the types.
|
||||
* \return A list of parameter types, one for each parameter given.
|
||||
* \throws rclcpp::exceptions::ParameterNotDeclaredException if any of the
|
||||
* parameters have not been declared and undeclared parameters are not
|
||||
* allowed.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<uint8_t>
|
||||
get_parameter_types(const std::vector<std::string> & names) const;
|
||||
|
||||
/// Return a list of parameters with any of the given prefixes, up to the given depth.
|
||||
/**
|
||||
* \todo: properly document and test this method.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const;
|
||||
|
||||
using OnParametersSetCallbackType =
|
||||
rclcpp::node_interfaces::NodeParametersInterface::OnParametersSetCallbackType;
|
||||
|
||||
/// Register a callback to be called anytime a parameter is about to be changed.
|
||||
/**
|
||||
* The callback signature is designed to allow handling of any of the above
|
||||
* `set_parameter*` or `declare_parameter*` methods, and so it takes a const
|
||||
* reference to a vector of parameters to be set, and returns an instance of
|
||||
* rcl_interfaces::msg::SetParametersResult to indicate whether or not the
|
||||
* parameter should be set or not, and if not why.
|
||||
*
|
||||
* For an example callback:
|
||||
*
|
||||
* rcl_interfaces::msg::SetParametersResult
|
||||
* my_callback(const std::vector<rclcpp::Parameter> & parameters)
|
||||
* {
|
||||
* rcl_interfaces::msg::SetParametersResult result;
|
||||
* result.successful = true;
|
||||
* for (const auto & parameter : parameters) {
|
||||
* if (!some_condition) {
|
||||
* result.successful = false;
|
||||
* result.reason = "the reason it could not be allowed";
|
||||
* }
|
||||
* }
|
||||
* return result;
|
||||
* }
|
||||
*
|
||||
* You can see that the SetParametersResult is a boolean flag for success
|
||||
* and an optional reason that can be used in error reporting when it fails.
|
||||
*
|
||||
* This allows the node developer to control which parameters may be changed.
|
||||
*
|
||||
* Note that the callback is called when declare_parameter() and its variants
|
||||
* are called, and so you cannot assume the parameter has been set before
|
||||
* this callback, so when checking a new value against the existing one, you
|
||||
* must account for the case where the parameter is not yet set.
|
||||
*
|
||||
* Some constraints like read_only are enforced before the callback is called.
|
||||
*
|
||||
* There may only be one callback set at a time, so the previously set
|
||||
* callback is returned when this method is used, or nullptr will be returned
|
||||
* if no callback was previously set.
|
||||
*
|
||||
* \param[in] callback The callback to be called when the value for a
|
||||
* parameter is about to be set.
|
||||
* \return The previous callback that was registered, if there was one,
|
||||
* otherwise nullptr.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::Node::OnParametersSetCallbackType
|
||||
set_on_parameters_set_callback(rclcpp::Node::OnParametersSetCallbackType callback);
|
||||
|
||||
/// Register the callback for parameter changes
|
||||
/**
|
||||
* \param[in] callback User defined callback function.
|
||||
* It is expected to atomically set parameters.
|
||||
* \note Repeated invocations of this function will overwrite previous callbacks
|
||||
* \note Repeated invocations of this function will overwrite previous callbacks.
|
||||
*/
|
||||
template<typename CallbackT>
|
||||
[[deprecated("use set_on_parameters_set_callback() instead")]]
|
||||
void
|
||||
register_param_change_callback(CallbackT && callback);
|
||||
|
||||
/// Get the fully-qualified names of all available nodes.
|
||||
/**
|
||||
* The fully-qualified name includes the local namespace and name of the node.
|
||||
* \return A vector of fully-qualified names of nodes.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<std::string>
|
||||
get_node_names() const;
|
||||
@@ -655,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.
|
||||
/**
|
||||
@@ -694,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>
|
||||
@@ -301,11 +245,60 @@ Node::create_service(
|
||||
group);
|
||||
}
|
||||
|
||||
template<typename CallbackT>
|
||||
void
|
||||
Node::register_param_change_callback(CallbackT && callback)
|
||||
template<typename ParameterT>
|
||||
auto
|
||||
Node::declare_parameter(
|
||||
const std::string & name,
|
||||
const ParameterT & default_value,
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor)
|
||||
{
|
||||
this->node_parameters_->register_param_change_callback(std::forward<CallbackT>(callback));
|
||||
return this->declare_parameter(
|
||||
name,
|
||||
rclcpp::ParameterValue(default_value),
|
||||
parameter_descriptor
|
||||
).get<ParameterT>();
|
||||
}
|
||||
|
||||
template<typename ParameterT>
|
||||
std::vector<ParameterT>
|
||||
Node::declare_parameters(
|
||||
const std::string & namespace_,
|
||||
const std::map<std::string, ParameterT> & parameters)
|
||||
{
|
||||
std::vector<ParameterT> result;
|
||||
std::string normalized_namespace = namespace_.empty() ? "" : (namespace_ + ".");
|
||||
std::transform(
|
||||
parameters.begin(), parameters.end(), std::back_inserter(result),
|
||||
[this, &normalized_namespace](auto element) {
|
||||
return this->declare_parameter(normalized_namespace + element.first, element.second);
|
||||
}
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename ParameterT>
|
||||
std::vector<ParameterT>
|
||||
Node::declare_parameters(
|
||||
const std::string & namespace_,
|
||||
const std::map<
|
||||
std::string,
|
||||
std::pair<ParameterT, rcl_interfaces::msg::ParameterDescriptor>
|
||||
> & parameters)
|
||||
{
|
||||
std::vector<ParameterT> result;
|
||||
std::string normalized_namespace = namespace_.empty() ? "" : (namespace_ + ".");
|
||||
std::transform(
|
||||
parameters.begin(), parameters.end(), std::back_inserter(result),
|
||||
[this, &normalized_namespace](auto element) {
|
||||
return static_cast<ParameterT>(
|
||||
this->declare_parameter(
|
||||
normalized_namespace + element.first,
|
||||
element.second.first,
|
||||
element.second.second)
|
||||
);
|
||||
}
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename ParameterT>
|
||||
@@ -314,33 +307,32 @@ Node::set_parameter_if_not_set(
|
||||
const std::string & name,
|
||||
const ParameterT & value)
|
||||
{
|
||||
std::string parameter_name_with_sub_namespace =
|
||||
extend_name_with_sub_namespace(name, this->get_sub_namespace());
|
||||
|
||||
rclcpp::Parameter parameter;
|
||||
if (!this->get_parameter(parameter_name_with_sub_namespace, parameter)) {
|
||||
this->set_parameters({
|
||||
rclcpp::Parameter(parameter_name_with_sub_namespace, value),
|
||||
});
|
||||
if (
|
||||
!this->has_parameter(name) ||
|
||||
this->describe_parameter(name).type == PARAMETER_NOT_SET)
|
||||
{
|
||||
this->set_parameter(rclcpp::Parameter(name, value));
|
||||
}
|
||||
}
|
||||
|
||||
// this is a partially-specialized version of set_parameter_if_not_set above,
|
||||
// where our concrete type for ParameterT is std::map, but the to-be-determined
|
||||
// type is the value in the map.
|
||||
template<typename MapValueT>
|
||||
template<typename ParameterT>
|
||||
void
|
||||
Node::set_parameters_if_not_set(
|
||||
const std::string & name,
|
||||
const std::map<std::string, MapValueT> & values)
|
||||
const std::map<std::string, ParameterT> & values)
|
||||
{
|
||||
std::vector<rclcpp::Parameter> params;
|
||||
|
||||
for (const auto & val : values) {
|
||||
std::string param_name = name + "." + val.first;
|
||||
rclcpp::Parameter parameter;
|
||||
if (!this->get_parameter(param_name, parameter)) {
|
||||
params.push_back(rclcpp::Parameter(param_name, val.second));
|
||||
std::string parameter_name = name + "." + val.first;
|
||||
if (
|
||||
!this->has_parameter(parameter_name) ||
|
||||
this->describe_parameter(parameter_name).type == PARAMETER_NOT_SET)
|
||||
{
|
||||
params.push_back(rclcpp::Parameter(parameter_name, val.second));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,35 +341,15 @@ Node::set_parameters_if_not_set(
|
||||
|
||||
template<typename ParameterT>
|
||||
bool
|
||||
Node::get_parameter(const std::string & name, ParameterT & value) const
|
||||
Node::get_parameter(const std::string & name, ParameterT & parameter) const
|
||||
{
|
||||
std::string sub_name = extend_name_with_sub_namespace(name, this->get_sub_namespace());
|
||||
|
||||
rclcpp::Parameter parameter;
|
||||
rclcpp::Parameter parameter_variant;
|
||||
|
||||
bool result = get_parameter(sub_name, parameter);
|
||||
bool result = get_parameter(sub_name, parameter_variant);
|
||||
if (result) {
|
||||
value = parameter.get_value<ParameterT>();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// this is a partially-specialized version of get_parameter above,
|
||||
// where our concrete type for ParameterT is std::map, but the to-be-determined
|
||||
// type is the value in the map.
|
||||
template<typename MapValueT>
|
||||
bool
|
||||
Node::get_parameters(
|
||||
const std::string & name,
|
||||
std::map<std::string, MapValueT> & values) const
|
||||
{
|
||||
std::map<std::string, rclcpp::Parameter> params;
|
||||
bool result = node_parameters_->get_parameters_by_prefix(name, params);
|
||||
if (result) {
|
||||
for (const auto & param : params) {
|
||||
values[param.first] = param.second.get_value<MapValueT>();
|
||||
}
|
||||
parameter = static_cast<ParameterT>(parameter_variant.get_value<ParameterT>());
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -387,18 +359,38 @@ template<typename ParameterT>
|
||||
bool
|
||||
Node::get_parameter_or(
|
||||
const std::string & name,
|
||||
ParameterT & value,
|
||||
ParameterT & parameter,
|
||||
const ParameterT & alternative_value) const
|
||||
{
|
||||
std::string sub_name = extend_name_with_sub_namespace(name, this->get_sub_namespace());
|
||||
|
||||
bool got_parameter = get_parameter(sub_name, value);
|
||||
bool got_parameter = get_parameter(sub_name, parameter);
|
||||
if (!got_parameter) {
|
||||
value = alternative_value;
|
||||
parameter = alternative_value;
|
||||
}
|
||||
return got_parameter;
|
||||
}
|
||||
|
||||
// this is a partially-specialized version of get_parameter above,
|
||||
// where our concrete type for ParameterT is std::map, but the to-be-determined
|
||||
// type is the value in the map.
|
||||
template<typename ParameterT>
|
||||
bool
|
||||
Node::get_parameters(
|
||||
const std::string & prefix,
|
||||
std::map<std::string, ParameterT> & values) const
|
||||
{
|
||||
std::map<std::string, rclcpp::Parameter> params;
|
||||
bool result = node_parameters_->get_parameters_by_prefix(prefix, params);
|
||||
if (result) {
|
||||
for (const auto & param : params) {
|
||||
values[param.first] = static_cast<ParameterT>(param.second.get_value<ParameterT>());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename ParameterT>
|
||||
void
|
||||
Node::get_parameter_or_set(
|
||||
@@ -417,6 +409,13 @@ Node::get_parameter_or_set(
|
||||
}
|
||||
}
|
||||
|
||||
template<typename CallbackT>
|
||||
void
|
||||
Node::register_param_change_callback(CallbackT && callback)
|
||||
{
|
||||
this->node_parameters_->register_param_change_callback(std::forward<CallbackT>(callback));
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_IMPL_HPP_
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__GET_NODE_BASE_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__GET_NODE_BASE_INTERFACE_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
|
||||
/// This header provides the get_node_base_interface() template function.
|
||||
/**
|
||||
* This function is useful for getting the NodeBaseInterface pointer from
|
||||
* various kinds of Node-like classes.
|
||||
*
|
||||
* It's able to get the NodeBaseInterface pointer so long as the class
|
||||
* has a method called ``get_node_base_interface()`` which returns
|
||||
* either a pointer (const or not) to a NodeBaseInterface or a
|
||||
* std::shared_ptr to a NodeBaseInterface.
|
||||
*/
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// This is a meta-programming checker for if a given Node-like object has a
|
||||
// getter called get_node_base_interface() which returns various types,
|
||||
// e.g. const pointer or a shared pointer.
|
||||
template<typename NodeType, typename ReturnType>
|
||||
struct has_get_node_base_interface
|
||||
{
|
||||
private:
|
||||
template<typename T>
|
||||
static constexpr
|
||||
auto
|
||||
check(T *)->typename std::is_same<
|
||||
decltype(std::declval<T>().get_node_base_interface()),
|
||||
ReturnType
|
||||
>::type;
|
||||
|
||||
template<typename>
|
||||
static constexpr
|
||||
std::false_type
|
||||
check(...);
|
||||
|
||||
public:
|
||||
using type = decltype(check<NodeType>(nullptr));
|
||||
static constexpr bool value = type::value;
|
||||
};
|
||||
|
||||
// If NodeType is a pointer to NodeBaseInterface already (just normal function overload).
|
||||
inline
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface_from_pointer(rclcpp::node_interfaces::NodeBaseInterface * pointer)
|
||||
{
|
||||
return pointer;
|
||||
}
|
||||
|
||||
// If NodeType has a method called get_node_base_interface() which returns a shared pointer.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<has_get_node_base_interface<
|
||||
typename std::remove_pointer<NodeType>::type,
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface>
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface_from_pointer(NodeType node_pointer)
|
||||
{
|
||||
return node_pointer->get_node_base_interface().get();
|
||||
}
|
||||
|
||||
// If NodeType has a method called get_node_base_interface() which returns a pointer.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<has_get_node_base_interface<
|
||||
typename std::remove_pointer<NodeType>::type,
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface_from_pointer(NodeType node_pointer)
|
||||
{
|
||||
return node_pointer->get_node_base_interface();
|
||||
}
|
||||
|
||||
// Forward shared_ptr's to const node pointer signatures.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<std::is_same<
|
||||
NodeType,
|
||||
typename std::shared_ptr<typename std::remove_pointer<NodeType>::type::element_type> *
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface_from_pointer(NodeType node_shared_pointer)
|
||||
{
|
||||
return get_node_base_interface_from_pointer(node_shared_pointer->get());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Get the NodeBaseInterface as a pointer from a pointer to a "Node like" object.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface(NodeType node_pointer)
|
||||
{
|
||||
// Forward pointers to detail implmentation directly.
|
||||
return detail::get_node_base_interface_from_pointer(node_pointer);
|
||||
}
|
||||
|
||||
/// Get the NodeBaseInterface as a pointer from a "Node like" object.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<
|
||||
!std::is_pointer<typename std::remove_reference<NodeType>::type>::value, int
|
||||
>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface(NodeType && node_reference)
|
||||
{
|
||||
// Forward references to detail implmentation as a pointer.
|
||||
return detail::get_node_base_interface_from_pointer(&node_reference);
|
||||
}
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__GET_NODE_BASE_INTERFACE_HPP_
|
||||
@@ -0,0 +1,149 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__GET_NODE_TIMERS_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__GET_NODE_TIMERS_INTERFACE_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
|
||||
|
||||
/// This header provides the get_node_timers_interface() template function.
|
||||
/**
|
||||
* This function is useful for getting the NodeTimersInterface pointer from
|
||||
* various kinds of Node-like classes.
|
||||
*
|
||||
* It's able to get the NodeTimersInterface pointer so long as the class
|
||||
* has a method called ``get_node_timers_interface()`` which returns
|
||||
* either a pointer (const or not) to a NodeTimersInterface or a
|
||||
* std::shared_ptr to a NodeTimersInterface.
|
||||
*/
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// This is a meta-programming checker for if a given Node-like object has a
|
||||
// getter called get_node_timers_interface() which returns various types,
|
||||
// e.g. const pointer or a shared pointer.
|
||||
template<typename NodeType, typename ReturnType>
|
||||
struct has_get_node_timers_interface
|
||||
{
|
||||
private:
|
||||
template<typename T>
|
||||
static constexpr
|
||||
auto
|
||||
check(T *)->typename std::is_same<
|
||||
decltype(std::declval<T>().get_node_timers_interface()),
|
||||
ReturnType
|
||||
>::type;
|
||||
|
||||
template<typename>
|
||||
static constexpr
|
||||
std::false_type
|
||||
check(...);
|
||||
|
||||
public:
|
||||
using type = decltype(check<NodeType>(nullptr));
|
||||
static constexpr bool value = type::value;
|
||||
};
|
||||
|
||||
// If NodeType is a pointer to NodeTimersInterface already (just normal function overload).
|
||||
inline
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface_from_pointer(rclcpp::node_interfaces::NodeTimersInterface * pointer)
|
||||
{
|
||||
return pointer;
|
||||
}
|
||||
|
||||
// If NodeType has a method called get_node_timers_interface() which returns a shared pointer.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<has_get_node_timers_interface<
|
||||
typename std::remove_pointer<NodeType>::type,
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeTimersInterface>
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface_from_pointer(NodeType node_pointer)
|
||||
{
|
||||
return node_pointer->get_node_timers_interface().get();
|
||||
}
|
||||
|
||||
// If NodeType has a method called get_node_timers_interface() which returns a pointer.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<has_get_node_timers_interface<
|
||||
typename std::remove_pointer<NodeType>::type,
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface_from_pointer(NodeType node_pointer)
|
||||
{
|
||||
return node_pointer->get_node_timers_interface();
|
||||
}
|
||||
|
||||
// Forward shared_ptr's to const node pointer signatures.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<std::is_same<
|
||||
NodeType,
|
||||
typename std::shared_ptr<typename std::remove_pointer<NodeType>::type::element_type> *
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface_from_pointer(NodeType node_shared_pointer)
|
||||
{
|
||||
return get_node_timers_interface_from_pointer(node_shared_pointer->get());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Get the NodeTimersInterface as a pointer from a pointer to a "Node like" object.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface(NodeType node_pointer)
|
||||
{
|
||||
// Forward pointers to detail implmentation directly.
|
||||
return detail::get_node_timers_interface_from_pointer(node_pointer);
|
||||
}
|
||||
|
||||
/// Get the NodeTimersInterface as a pointer from a "Node like" object.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<
|
||||
!std::is_pointer<typename std::remove_reference<NodeType>::type>::value, int
|
||||
>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface(NodeType && node_reference)
|
||||
{
|
||||
// Forward references to detail implmentation as a pointer.
|
||||
return detail::get_node_timers_interface_from_pointer(&node_reference);
|
||||
}
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__GET_NODE_TIMERS_INTERFACE_HPP_
|
||||
@@ -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
|
||||
|
||||
@@ -40,6 +40,16 @@ namespace rclcpp
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
// Internal struct for holding useful info about parameters
|
||||
struct ParameterInfo
|
||||
{
|
||||
/// Current value of the parameter.
|
||||
rclcpp::ParameterValue value;
|
||||
|
||||
/// A description of the parameter
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
};
|
||||
|
||||
/// Implementation of the NodeParameters part of the Node API.
|
||||
class NodeParameters : public NodeParametersInterface
|
||||
{
|
||||
@@ -49,83 +59,104 @@ public:
|
||||
RCLCPP_PUBLIC
|
||||
NodeParameters(
|
||||
const node_interfaces::NodeBaseInterface::SharedPtr node_base,
|
||||
const node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
|
||||
const node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
|
||||
const node_interfaces::NodeServicesInterface::SharedPtr node_services,
|
||||
const node_interfaces::NodeClockInterface::SharedPtr node_clock,
|
||||
const std::vector<Parameter> & initial_parameters,
|
||||
bool use_intra_process,
|
||||
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_parameters_from_overrides);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
~NodeParameters();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
const rclcpp::ParameterValue &
|
||||
declare_parameter(
|
||||
const std::string & name,
|
||||
const rclcpp::ParameterValue & default_value,
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
undeclare_parameter(const std::string & name) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
has_parameter(const std::string & name) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
set_parameters(
|
||||
const std::vector<rclcpp::Parameter> & parameters);
|
||||
const std::vector<rclcpp::Parameter> & parameters) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
set_parameters_atomically(
|
||||
const std::vector<rclcpp::Parameter> & parameters);
|
||||
const std::vector<rclcpp::Parameter> & parameters) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::vector<rclcpp::Parameter>
|
||||
get_parameters(const std::vector<std::string> & names) const;
|
||||
get_parameters(const std::vector<std::string> & names) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::Parameter
|
||||
get_parameter(const std::string & name) const;
|
||||
get_parameter(const std::string & name) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
bool
|
||||
get_parameter(
|
||||
const std::string & name,
|
||||
rclcpp::Parameter & parameter) const;
|
||||
rclcpp::Parameter & parameter) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
bool
|
||||
get_parameters_by_prefix(
|
||||
const std::string & prefix,
|
||||
std::map<std::string, rclcpp::Parameter> & parameters) const;
|
||||
std::map<std::string, rclcpp::Parameter> & parameters) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::vector<rcl_interfaces::msg::ParameterDescriptor>
|
||||
describe_parameters(const std::vector<std::string> & names) const;
|
||||
describe_parameters(const std::vector<std::string> & names) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::vector<uint8_t>
|
||||
get_parameter_types(const std::vector<std::string> & names) const;
|
||||
get_parameter_types(const std::vector<std::string> & names) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const;
|
||||
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
OnParametersSetCallbackType
|
||||
set_on_parameters_set_callback(OnParametersSetCallbackType callback) override;
|
||||
|
||||
[[deprecated("use set_on_parameters_set_callback() instead")]]
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
register_param_change_callback(ParametersCallbackFunction callback);
|
||||
register_param_change_callback(OnParametersSetCallbackType callback) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::map<std::string, rclcpp::ParameterValue> &
|
||||
get_parameter_overrides() const override;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(NodeParameters)
|
||||
|
||||
mutable std::mutex mutex_;
|
||||
|
||||
ParametersCallbackFunction parameters_callback_ = nullptr;
|
||||
OnParametersSetCallbackType on_parameters_set_callback_ = nullptr;
|
||||
|
||||
std::map<std::string, rclcpp::Parameter> parameters_;
|
||||
std::map<std::string, ParameterInfo> parameters_;
|
||||
|
||||
std::map<std::string, rclcpp::ParameterValue> parameter_overrides_;
|
||||
|
||||
bool allow_undeclared_ = false;
|
||||
|
||||
Publisher<rcl_interfaces::msg::ParameterEvent>::SharedPtr events_publisher_;
|
||||
|
||||
@@ -133,6 +164,7 @@ private:
|
||||
|
||||
std::string combined_name_;
|
||||
|
||||
node_interfaces::NodeLoggingInterface::SharedPtr node_logging_;
|
||||
node_interfaces::NodeClockInterface::SharedPtr node_clock_;
|
||||
};
|
||||
|
||||
|
||||
@@ -42,12 +42,50 @@ public:
|
||||
virtual
|
||||
~NodeParametersInterface() = default;
|
||||
|
||||
/// Declare and initialize a parameter.
|
||||
/**
|
||||
* \sa rclcpp::Node::declare_parameter
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
const rclcpp::ParameterValue &
|
||||
declare_parameter(
|
||||
const std::string & name,
|
||||
const rclcpp::ParameterValue & default_value = rclcpp::ParameterValue(),
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
|
||||
rcl_interfaces::msg::ParameterDescriptor()) = 0;
|
||||
|
||||
/// Undeclare a parameter.
|
||||
/**
|
||||
* \sa rclcpp::Node::undeclare_parameter
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
undeclare_parameter(const std::string & name) = 0;
|
||||
|
||||
/// Return true if the parameter has been declared, otherwise false.
|
||||
/**
|
||||
* \sa rclcpp::Node::has_parameter
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
bool
|
||||
has_parameter(const std::string & name) const = 0;
|
||||
|
||||
/// Set one or more parameters, one at a time.
|
||||
/**
|
||||
* \sa rclcpp::Node::set_parameters
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
set_parameters(
|
||||
const std::vector<rclcpp::Parameter> & parameters) = 0;
|
||||
set_parameters(const std::vector<rclcpp::Parameter> & parameters) = 0;
|
||||
|
||||
/// Set and initialize a parameter, all at once.
|
||||
/**
|
||||
* \sa rclcpp::Node::set_parameters_atomically
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
@@ -119,14 +157,34 @@ public:
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const = 0;
|
||||
|
||||
using ParametersCallbackFunction = std::function<
|
||||
rcl_interfaces::msg::SetParametersResult(
|
||||
const std::vector<rclcpp::Parameter> &)>;
|
||||
using OnParametersSetCallbackType =
|
||||
std::function<
|
||||
rcl_interfaces::msg::SetParametersResult(const std::vector<rclcpp::Parameter> &)
|
||||
>;
|
||||
|
||||
using ParametersCallbackFunction [[deprecated("use OnParametersSetCallbackType instead")]] =
|
||||
OnParametersSetCallbackType;
|
||||
|
||||
/// Register a callback for when parameters are being set, return an existing one.
|
||||
/**
|
||||
* \sa rclcpp::Node::set_on_parameters_set_callback
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
OnParametersSetCallbackType
|
||||
set_on_parameters_set_callback(OnParametersSetCallbackType callback) = 0;
|
||||
|
||||
[[deprecated("use set_on_parameters_set_callback() instead")]]
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
register_param_change_callback(ParametersCallbackFunction callback) = 0;
|
||||
register_param_change_callback(OnParametersSetCallbackType callback) = 0;
|
||||
|
||||
/// Return the initial parameter values used by the NodeParameters to override default values.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
const std::map<std::string, rclcpp::ParameterValue> &
|
||||
get_parameter_overrides() const = 0;
|
||||
};
|
||||
|
||||
} // 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,12 +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_parameters_from_overrides = false
|
||||
* - allocator = rcl_get_default_allocator()
|
||||
*
|
||||
* \param[in] allocator allocator to use in construction of NodeOptions.
|
||||
@@ -101,37 +107,37 @@ 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;
|
||||
}
|
||||
|
||||
/// Return a reference to the use_global_arguments flag.
|
||||
/// Return the use_global_arguments flag.
|
||||
RCLCPP_PUBLIC
|
||||
const bool &
|
||||
bool
|
||||
use_global_arguments() const;
|
||||
|
||||
/// Set the use_global_arguments flag, return this for parameter idiom.
|
||||
@@ -144,11 +150,11 @@ public:
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
NodeOptions &
|
||||
use_global_arguments(const bool & use_global_arguments);
|
||||
use_global_arguments(bool use_global_arguments);
|
||||
|
||||
/// Return a reference to the use_intra_process_comms flag
|
||||
/// Return the use_intra_process_comms flag.
|
||||
RCLCPP_PUBLIC
|
||||
const bool &
|
||||
bool
|
||||
use_intra_process_comms() const;
|
||||
|
||||
/// Set the use_intra_process_comms flag, return this for parameter idiom.
|
||||
@@ -163,11 +169,11 @@ public:
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
NodeOptions &
|
||||
use_intra_process_comms(const bool & use_intra_process_comms);
|
||||
use_intra_process_comms(bool use_intra_process_comms);
|
||||
|
||||
/// Return a reference to the start_parameter_services flag
|
||||
/// Return the start_parameter_services flag.
|
||||
RCLCPP_PUBLIC
|
||||
const bool &
|
||||
bool
|
||||
start_parameter_services() const;
|
||||
|
||||
/// Set the start_parameter_services flag, return this for parameter idiom.
|
||||
@@ -182,11 +188,11 @@ public:
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
NodeOptions &
|
||||
start_parameter_services(const bool & start_parameter_services);
|
||||
start_parameter_services(bool start_parameter_services);
|
||||
|
||||
/// Return a reference to the start_parameter_event_publisher flag.
|
||||
/// Return the start_parameter_event_publisher flag.
|
||||
RCLCPP_PUBLIC
|
||||
const bool &
|
||||
bool
|
||||
start_parameter_event_publisher() const;
|
||||
|
||||
/// Set the start_parameter_event_publisher flag, return this for parameter idiom.
|
||||
@@ -198,20 +204,78 @@ public:
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
NodeOptions &
|
||||
start_parameter_event_publisher(const bool & start_parameter_event_publisher);
|
||||
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
|
||||
bool
|
||||
allow_undeclared_parameters() const;
|
||||
|
||||
/// Set the allow_undeclared_parameters, return this for parameter idiom.
|
||||
/**
|
||||
* If true, allow any parameter name to be set on the node without first
|
||||
* being declared.
|
||||
* Otherwise, setting an undeclared parameter will raise an exception.
|
||||
*
|
||||
* 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_parameters_from_overrides flag.
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
automatically_declare_parameters_from_overrides() const;
|
||||
|
||||
/// Set the automatically_declare_parameters_from_overrides, return this.
|
||||
/**
|
||||
* 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 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_parameters_from_overrides(
|
||||
bool automatically_declare_parameters_from_overrides);
|
||||
|
||||
/// Return the rcl_allocator_t to be used.
|
||||
RCLCPP_PUBLIC
|
||||
@@ -244,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};
|
||||
|
||||
@@ -254,7 +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_parameters_from_overrides_ {false};
|
||||
|
||||
rcl_allocator_t allocator_ {rcl_get_default_allocator()};
|
||||
};
|
||||
|
||||
@@ -28,21 +28,59 @@
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
class Parameter;
|
||||
|
||||
namespace node_interfaces
|
||||
{
|
||||
struct ParameterInfo;
|
||||
} // namespace node_interfaces
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// This helper function is required because you cannot do specialization on a
|
||||
// class method, so instead we specialize this template function and call it
|
||||
// from the unspecialized, but dependent, class method.
|
||||
template<typename T>
|
||||
auto
|
||||
get_value_helper(const rclcpp::Parameter * parameter);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Structure to store an arbitrary parameter with templated get/set methods.
|
||||
class Parameter
|
||||
{
|
||||
public:
|
||||
/// Construct with an empty name and a parameter value of type rclcpp::PARAMETER_NOT_SET.
|
||||
RCLCPP_PUBLIC
|
||||
Parameter();
|
||||
|
||||
/// Construct with given name and a parameter value of type rclcpp::PARAMETER_NOT_SET.
|
||||
RCLCPP_PUBLIC
|
||||
explicit Parameter(const std::string & name);
|
||||
|
||||
/// Construct with given name and given parameter value.
|
||||
RCLCPP_PUBLIC
|
||||
Parameter(const std::string & name, const ParameterValue & value);
|
||||
|
||||
/// Construct with given name and given parameter value.
|
||||
template<typename ValueTypeT>
|
||||
explicit Parameter(const std::string & name, ValueTypeT value)
|
||||
Parameter(const std::string & name, ValueTypeT value)
|
||||
: Parameter(name, ParameterValue(value))
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
explicit Parameter(const rclcpp::node_interfaces::ParameterInfo & parameter_info);
|
||||
|
||||
/// Equal operator.
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
operator==(const Parameter & rhs) const;
|
||||
|
||||
/// Not equal operator.
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
operator!=(const Parameter & rhs) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
ParameterType
|
||||
@@ -60,6 +98,11 @@ public:
|
||||
rcl_interfaces::msg::ParameterValue
|
||||
get_value_message() const;
|
||||
|
||||
/// Get the internal storage for the parameter value.
|
||||
RCLCPP_PUBLIC
|
||||
const rclcpp::ParameterValue &
|
||||
get_parameter_value() const;
|
||||
|
||||
/// Get value of parameter using rclcpp::ParameterType as template argument.
|
||||
template<ParameterType ParamT>
|
||||
decltype(auto)
|
||||
@@ -71,10 +114,7 @@ public:
|
||||
/// Get value of parameter using c++ types as template argument.
|
||||
template<typename T>
|
||||
decltype(auto)
|
||||
get_value() const
|
||||
{
|
||||
return value_.get<T>();
|
||||
}
|
||||
get_value() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
@@ -142,6 +182,49 @@ RCLCPP_PUBLIC
|
||||
std::ostream &
|
||||
operator<<(std::ostream & os, const std::vector<Parameter> & parameters);
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
auto
|
||||
get_value_helper(const rclcpp::Parameter * parameter)
|
||||
{
|
||||
return parameter->get_parameter_value().get<T>();
|
||||
}
|
||||
|
||||
// Specialization allowing Parameter::get() to return a const ref to the parameter value object.
|
||||
template<>
|
||||
inline
|
||||
auto
|
||||
get_value_helper<rclcpp::ParameterValue>(const rclcpp::Parameter * parameter)
|
||||
{
|
||||
return parameter->get_parameter_value();
|
||||
}
|
||||
|
||||
// Specialization allowing Parameter::get() to return a const ref to the parameter itself.
|
||||
template<>
|
||||
inline
|
||||
auto
|
||||
get_value_helper<rclcpp::Parameter>(const rclcpp::Parameter * parameter)
|
||||
{
|
||||
// Use this lambda to ensure it's a const reference being returned (and not a copy).
|
||||
auto type_enforcing_lambda =
|
||||
[¶meter]() -> const rclcpp::Parameter & {
|
||||
return *parameter;
|
||||
};
|
||||
return type_enforcing_lambda();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
decltype(auto)
|
||||
Parameter::get_value() const
|
||||
{
|
||||
// use the helper to specialize for the ParameterValue and Parameter cases.
|
||||
return detail::get_value_helper<T>(this);
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
namespace std
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
explicit ParameterService(
|
||||
const std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
|
||||
const std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
|
||||
node_interfaces::NodeParametersInterface * node_params,
|
||||
rclcpp::node_interfaces::NodeParametersInterface * node_params,
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters);
|
||||
|
||||
private:
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
enum ParameterType
|
||||
|
||||
enum ParameterType : uint8_t
|
||||
{
|
||||
PARAMETER_NOT_SET = rcl_interfaces::msg::ParameterType::PARAMETER_NOT_SET,
|
||||
PARAMETER_BOOL = rcl_interfaces::msg::ParameterType::PARAMETER_BOOL,
|
||||
@@ -45,11 +46,11 @@ enum ParameterType
|
||||
/// Return the name of a parameter type
|
||||
RCLCPP_PUBLIC
|
||||
std::string
|
||||
to_string(const ParameterType type);
|
||||
to_string(ParameterType type);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::ostream &
|
||||
operator<<(std::ostream & os, const ParameterType type);
|
||||
operator<<(std::ostream & os, ParameterType type);
|
||||
|
||||
/// Indicate the parameter type does not match the expected type.
|
||||
class ParameterTypeException : public std::runtime_error
|
||||
@@ -129,10 +130,21 @@ public:
|
||||
rcl_interfaces::msg::ParameterValue
|
||||
to_value_msg() const;
|
||||
|
||||
/// Equal operator.
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
operator==(const ParameterValue & rhs) const;
|
||||
|
||||
/// Not equal operator.
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
operator!=(const ParameterValue & rhs) const;
|
||||
|
||||
// The following get() variants require the use of ParameterType
|
||||
|
||||
template<ParameterType type>
|
||||
typename std::enable_if<type == ParameterType::PARAMETER_BOOL, bool>::type
|
||||
constexpr
|
||||
typename std::enable_if<type == ParameterType::PARAMETER_BOOL, const bool &>::type
|
||||
get() const
|
||||
{
|
||||
if (value_.type != rcl_interfaces::msg::ParameterType::PARAMETER_BOOL) {
|
||||
@@ -142,7 +154,8 @@ public:
|
||||
}
|
||||
|
||||
template<ParameterType type>
|
||||
typename std::enable_if<type == ParameterType::PARAMETER_INTEGER, int64_t>::type
|
||||
constexpr
|
||||
typename std::enable_if<type == ParameterType::PARAMETER_INTEGER, const int64_t &>::type
|
||||
get() const
|
||||
{
|
||||
if (value_.type != rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER) {
|
||||
@@ -152,7 +165,8 @@ public:
|
||||
}
|
||||
|
||||
template<ParameterType type>
|
||||
typename std::enable_if<type == ParameterType::PARAMETER_DOUBLE, double>::type
|
||||
constexpr
|
||||
typename std::enable_if<type == ParameterType::PARAMETER_DOUBLE, const double &>::type
|
||||
get() const
|
||||
{
|
||||
if (value_.type != rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE) {
|
||||
@@ -162,6 +176,7 @@ public:
|
||||
}
|
||||
|
||||
template<ParameterType type>
|
||||
constexpr
|
||||
typename std::enable_if<type == ParameterType::PARAMETER_STRING, const std::string &>::type
|
||||
get() const
|
||||
{
|
||||
@@ -172,6 +187,7 @@ public:
|
||||
}
|
||||
|
||||
template<ParameterType type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
type == ParameterType::PARAMETER_BYTE_ARRAY, const std::vector<uint8_t> &>::type
|
||||
get() const
|
||||
@@ -183,6 +199,7 @@ public:
|
||||
}
|
||||
|
||||
template<ParameterType type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
type == ParameterType::PARAMETER_BOOL_ARRAY, const std::vector<bool> &>::type
|
||||
get() const
|
||||
@@ -194,6 +211,7 @@ public:
|
||||
}
|
||||
|
||||
template<ParameterType type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
type == ParameterType::PARAMETER_INTEGER_ARRAY, const std::vector<int64_t> &>::type
|
||||
get() const
|
||||
@@ -205,6 +223,7 @@ public:
|
||||
}
|
||||
|
||||
template<ParameterType type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
type == ParameterType::PARAMETER_DOUBLE_ARRAY, const std::vector<double> &>::type
|
||||
get() const
|
||||
@@ -216,6 +235,7 @@ public:
|
||||
}
|
||||
|
||||
template<ParameterType type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
type == ParameterType::PARAMETER_STRING_ARRAY, const std::vector<std::string> &>::type
|
||||
get() const
|
||||
@@ -229,28 +249,32 @@ public:
|
||||
// The following get() variants allow the use of primitive types
|
||||
|
||||
template<typename type>
|
||||
typename std::enable_if<std::is_same<type, bool>::value, bool>::type
|
||||
constexpr
|
||||
typename std::enable_if<std::is_same<type, bool>::value, const bool &>::type
|
||||
get() const
|
||||
{
|
||||
return get<ParameterType::PARAMETER_BOOL>();
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
std::is_integral<type>::value && !std::is_same<type, bool>::value, int64_t>::type
|
||||
std::is_integral<type>::value && !std::is_same<type, bool>::value, const int64_t &>::type
|
||||
get() const
|
||||
{
|
||||
return get<ParameterType::PARAMETER_INTEGER>();
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
typename std::enable_if<std::is_floating_point<type>::value, double>::type
|
||||
constexpr
|
||||
typename std::enable_if<std::is_floating_point<type>::value, const double &>::type
|
||||
get() const
|
||||
{
|
||||
return get<ParameterType::PARAMETER_DOUBLE>();
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
constexpr
|
||||
typename std::enable_if<std::is_convertible<type, std::string>::value, const std::string &>::type
|
||||
get() const
|
||||
{
|
||||
@@ -258,6 +282,7 @@ public:
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
std::is_convertible<
|
||||
type, const std::vector<uint8_t> &>::value, const std::vector<uint8_t> &>::type
|
||||
@@ -267,6 +292,7 @@ public:
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
std::is_convertible<
|
||||
type, const std::vector<bool> &>::value, const std::vector<bool> &>::type
|
||||
@@ -276,6 +302,7 @@ public:
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
std::is_convertible<
|
||||
type, const std::vector<int64_t> &>::value, const std::vector<int64_t> &>::type
|
||||
@@ -285,6 +312,7 @@ public:
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
std::is_convertible<
|
||||
type, const std::vector<double> &>::value, const std::vector<double> &>::type
|
||||
@@ -294,6 +322,7 @@ public:
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
std::is_convertible<
|
||||
type, const std::vector<std::string> &>::value, const std::vector<std::string> &>::type
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -58,6 +58,16 @@ public:
|
||||
void
|
||||
cancel();
|
||||
|
||||
/// Return the timer cancellation state.
|
||||
/**
|
||||
* \return true if the timer has been cancelled, false otherwise
|
||||
* \throws std::runtime_error if the rcl_get_error_state returns 0
|
||||
* \throws RCLErrorBase some child class exception based on ret
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
is_canceled();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
reset();
|
||||
@@ -116,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,
|
||||
|
||||
@@ -18,17 +18,14 @@
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/init_options.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
#include "rmw/macros.h"
|
||||
#include "rmw/rmw.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace std
|
||||
@@ -104,6 +101,7 @@ uninstall_signal_handlers();
|
||||
*
|
||||
* \sa rclcpp::Context::init() for more details on arguments and possible exceptions
|
||||
* \returns Members of the argument vector that are not ROS arguments.
|
||||
* \throws anything remove_ros_arguments can throw
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<std::string>
|
||||
@@ -122,6 +120,8 @@ init_and_remove_ros_arguments(
|
||||
* \param[in] argc Number of arguments.
|
||||
* \param[in] argv Argument vector.
|
||||
* \returns Members of the argument vector that are not ROS arguments.
|
||||
* \throws anything throw_from_rcl_error can throw
|
||||
* \throws rclcpp::exceptions::RCLErrorBase if the parsing fails
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<std::string>
|
||||
|
||||
@@ -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.0</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>
|
||||
|
||||
@@ -95,7 +95,7 @@ def is_supported_feature_combination(feature_combination):
|
||||
#define RCLCPP_@(severity)@(suffix)(logger, @(''.join([p + ', ' for p in get_macro_parameters(feature_combination).keys()]))...) \
|
||||
do { \
|
||||
static_assert( \
|
||||
::std::is_same<typename std::remove_reference<decltype(logger)>::type, \
|
||||
::std::is_same<typename std::remove_reference<typename std::remove_cv<decltype(logger)>::type>::type, \
|
||||
typename ::rclcpp::Logger>::value, \
|
||||
"First argument to logging macros must be an rclcpp::Logger"); \
|
||||
RCUTILS_LOG_@(severity)@(suffix)_NAMED( \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -39,8 +39,8 @@ NameValidationError::format_error(
|
||||
return msg;
|
||||
}
|
||||
|
||||
void
|
||||
throw_from_rcl_error(
|
||||
std::exception_ptr
|
||||
from_rcl_error(
|
||||
rcl_ret_t ret,
|
||||
const std::string & prefix,
|
||||
const rcl_error_state_t * error_state,
|
||||
@@ -55,9 +55,9 @@ throw_from_rcl_error(
|
||||
if (!error_state) {
|
||||
throw std::runtime_error("rcl error state is not set");
|
||||
}
|
||||
std::string formated_prefix = prefix;
|
||||
std::string formatted_prefix = prefix;
|
||||
if (!prefix.empty()) {
|
||||
formated_prefix += ": ";
|
||||
formatted_prefix += ": ";
|
||||
}
|
||||
RCLErrorBase base_exc(ret, error_state);
|
||||
if (reset_error) {
|
||||
@@ -65,14 +65,28 @@ throw_from_rcl_error(
|
||||
}
|
||||
switch (ret) {
|
||||
case RCL_RET_BAD_ALLOC:
|
||||
throw RCLBadAlloc(base_exc);
|
||||
return std::make_exception_ptr(RCLBadAlloc(base_exc));
|
||||
case RCL_RET_INVALID_ARGUMENT:
|
||||
throw RCLInvalidArgument(base_exc, formated_prefix);
|
||||
return std::make_exception_ptr(RCLInvalidArgument(base_exc, formatted_prefix));
|
||||
default:
|
||||
throw RCLError(base_exc, formated_prefix);
|
||||
return std::make_exception_ptr(RCLError(base_exc, formatted_prefix));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
throw_from_rcl_error(
|
||||
rcl_ret_t ret,
|
||||
const std::string & prefix,
|
||||
const rcl_error_state_t * error_state,
|
||||
void (* reset_error)())
|
||||
{
|
||||
// We expect this to either throw a standard error,
|
||||
// or to generate an error pointer (which is caught
|
||||
// in err, and immediately thrown)
|
||||
auto err = from_rcl_error(ret, prefix, error_state, reset_error);
|
||||
std::rethrow_exception(err);
|
||||
}
|
||||
|
||||
RCLErrorBase::RCLErrorBase(rcl_ret_t ret, const rcl_error_state_t * error_state)
|
||||
: ret(ret), message(error_state->message), file(error_state->file), line(error_state->line_number),
|
||||
formatted_message(rcl_get_error_string().str)
|
||||
|
||||
@@ -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);
|
||||
@@ -101,5 +106,8 @@ MultiThreadedExecutor::run(size_t)
|
||||
scheduled_timers_.erase(it);
|
||||
}
|
||||
}
|
||||
// Clear the callback_group to prevent the AnyExecutable destructor from
|
||||
// resetting the callback group `can_be_taken_from`
|
||||
any_exec.callback_group.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -27,7 +27,17 @@
|
||||
#include "rclcpp/node_interfaces/node_clock.hpp"
|
||||
#include "rclcpp/node_interfaces/node_graph.hpp"
|
||||
#include "rclcpp/node_interfaces/node_logging.hpp"
|
||||
// When compiling this file, Windows produces a deprecation warning for the
|
||||
// deprecated function prototype of NodeParameters::register_param_change_callback().
|
||||
// Other compilers do not.
|
||||
#if defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
#include "rclcpp/node_interfaces/node_parameters.hpp"
|
||||
#if defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
#include "rclcpp/node_interfaces/node_services.hpp"
|
||||
#include "rclcpp/node_interfaces/node_time_source.hpp"
|
||||
#include "rclcpp/node_interfaces/node_timers.hpp"
|
||||
@@ -99,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())),
|
||||
@@ -114,14 +128,17 @@ Node::Node(
|
||||
)),
|
||||
node_parameters_(new rclcpp::node_interfaces::NodeParameters(
|
||||
node_base_,
|
||||
node_logging_,
|
||||
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_parameters_from_overrides()
|
||||
)),
|
||||
node_time_source_(new rclcpp::node_interfaces::NodeTimeSource(
|
||||
node_base_,
|
||||
@@ -215,20 +232,57 @@ Node::group_in_node(rclcpp::callback_group::CallbackGroup::SharedPtr group)
|
||||
return node_base_->callback_group_in_node(group);
|
||||
}
|
||||
|
||||
const rclcpp::ParameterValue &
|
||||
Node::declare_parameter(
|
||||
const std::string & name,
|
||||
const rclcpp::ParameterValue & default_value,
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor)
|
||||
{
|
||||
return this->node_parameters_->declare_parameter(name, default_value, parameter_descriptor);
|
||||
}
|
||||
|
||||
void
|
||||
Node::undeclare_parameter(const std::string & name)
|
||||
{
|
||||
this->node_parameters_->undeclare_parameter(name);
|
||||
}
|
||||
|
||||
bool
|
||||
Node::has_parameter(const std::string & name) const
|
||||
{
|
||||
return this->node_parameters_->has_parameter(name);
|
||||
}
|
||||
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
Node::set_parameter(const rclcpp::Parameter & parameter)
|
||||
{
|
||||
return this->set_parameters_atomically({parameter});
|
||||
}
|
||||
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
Node::set_parameters(
|
||||
const std::vector<rclcpp::Parameter> & parameters)
|
||||
Node::set_parameters(const std::vector<rclcpp::Parameter> & parameters)
|
||||
{
|
||||
return node_parameters_->set_parameters(parameters);
|
||||
}
|
||||
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
Node::set_parameters_atomically(
|
||||
const std::vector<rclcpp::Parameter> & parameters)
|
||||
Node::set_parameters_atomically(const std::vector<rclcpp::Parameter> & parameters)
|
||||
{
|
||||
return node_parameters_->set_parameters_atomically(parameters);
|
||||
}
|
||||
|
||||
rclcpp::Parameter
|
||||
Node::get_parameter(const std::string & name) const
|
||||
{
|
||||
return node_parameters_->get_parameter(name);
|
||||
}
|
||||
|
||||
bool
|
||||
Node::get_parameter(const std::string & name, rclcpp::Parameter & parameter) const
|
||||
{
|
||||
return node_parameters_->get_parameter(name, parameter);
|
||||
}
|
||||
|
||||
std::vector<rclcpp::Parameter>
|
||||
Node::get_parameters(
|
||||
const std::vector<std::string> & names) const
|
||||
@@ -236,40 +290,43 @@ Node::get_parameters(
|
||||
return node_parameters_->get_parameters(names);
|
||||
}
|
||||
|
||||
rclcpp::Parameter
|
||||
Node::get_parameter(const std::string & name) const
|
||||
rcl_interfaces::msg::ParameterDescriptor
|
||||
Node::describe_parameter(const std::string & name) const
|
||||
{
|
||||
return node_parameters_->get_parameter(name);
|
||||
}
|
||||
|
||||
bool Node::get_parameter(
|
||||
const std::string & name,
|
||||
rclcpp::Parameter & parameter) const
|
||||
{
|
||||
return node_parameters_->get_parameter(name, parameter);
|
||||
auto result = node_parameters_->describe_parameters({name});
|
||||
if (0 == result.size()) {
|
||||
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
|
||||
}
|
||||
if (result.size() > 1) {
|
||||
throw std::runtime_error("number of described parameters unexpectedly more than one");
|
||||
}
|
||||
return result.front();
|
||||
}
|
||||
|
||||
std::vector<rcl_interfaces::msg::ParameterDescriptor>
|
||||
Node::describe_parameters(
|
||||
const std::vector<std::string> & names) const
|
||||
Node::describe_parameters(const std::vector<std::string> & names) const
|
||||
{
|
||||
return node_parameters_->describe_parameters(names);
|
||||
}
|
||||
|
||||
std::vector<uint8_t>
|
||||
Node::get_parameter_types(
|
||||
const std::vector<std::string> & names) const
|
||||
Node::get_parameter_types(const std::vector<std::string> & names) const
|
||||
{
|
||||
return node_parameters_->get_parameter_types(names);
|
||||
}
|
||||
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
Node::list_parameters(
|
||||
const std::vector<std::string> & prefixes, uint64_t depth) const
|
||||
Node::list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const
|
||||
{
|
||||
return node_parameters_->list_parameters(prefixes, depth);
|
||||
}
|
||||
|
||||
rclcpp::Node::OnParametersSetCallbackType
|
||||
Node::set_on_parameters_set_callback(rclcpp::Node::OnParametersSetCallbackType callback)
|
||||
{
|
||||
return node_parameters_->set_on_parameters_set_callback(callback);
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
Node::get_node_names() const
|
||||
{
|
||||
@@ -417,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);
|
||||
|
||||
@@ -12,10 +12,23 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// When compiling this file, Windows produces a deprecation warning for the
|
||||
// deprecated function prototype of NodeParameters::register_param_change_callback().
|
||||
// Other compilers do not.
|
||||
#if defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
#include "rclcpp/node_interfaces/node_parameters.hpp"
|
||||
#if defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include <rcl_yaml_param_parser/parser.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
@@ -34,21 +47,29 @@ using rclcpp::node_interfaces::NodeParameters;
|
||||
|
||||
NodeParameters::NodeParameters(
|
||||
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
|
||||
const rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
|
||||
const rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
|
||||
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)
|
||||
: events_publisher_(nullptr), node_clock_(node_clock)
|
||||
const rclcpp::QoS & parameter_event_qos,
|
||||
const rclcpp::PublisherOptionsBase & parameter_event_publisher_options,
|
||||
bool allow_undeclared_parameters,
|
||||
bool automatically_declare_parameters_from_overrides)
|
||||
: allow_undeclared_(allow_undeclared_parameters),
|
||||
events_publisher_(nullptr),
|
||||
node_logging_(node_logging),
|
||||
node_clock_(node_clock)
|
||||
{
|
||||
using MessageT = rcl_interfaces::msg::ParameterEvent;
|
||||
using PublisherT = rclcpp::Publisher<MessageT>;
|
||||
using AllocatorT = std::allocator<void>;
|
||||
// TODO(wjwwood): expose this allocator through the Parameter interface.
|
||||
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);
|
||||
@@ -56,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
|
||||
@@ -105,20 +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;
|
||||
}
|
||||
|
||||
std::map<std::string, rclcpp::Parameter> parameters;
|
||||
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
|
||||
@@ -137,34 +144,35 @@ 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) {
|
||||
parameters[param.get_name()] = param;
|
||||
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) {
|
||||
parameters[param.get_name()] = param;
|
||||
// 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());
|
||||
}
|
||||
|
||||
std::vector<rclcpp::Parameter> combined_values;
|
||||
combined_values.reserve(parameters.size());
|
||||
for (auto & kv : parameters) {
|
||||
combined_values.emplace_back(kv.second);
|
||||
}
|
||||
|
||||
// TODO(sloretz) store initial values and use them when a parameter is created ros2/rclcpp#475
|
||||
// Set initial parameter values
|
||||
if (!combined_values.empty()) {
|
||||
rcl_interfaces::msg::SetParametersResult result = set_parameters_atomically(combined_values);
|
||||
if (!result.successful) {
|
||||
throw std::runtime_error("Failed to set initial parameters");
|
||||
// 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_parameters_from_overrides) {
|
||||
for (const auto & pair : this->get_parameter_overrides()) {
|
||||
if (!this->has_parameter(pair.first)) {
|
||||
this->declare_parameter(
|
||||
pair.first,
|
||||
pair.second,
|
||||
rcl_interfaces::msg::ParameterDescriptor());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,75 +180,459 @@ NodeParameters::NodeParameters(
|
||||
NodeParameters::~NodeParameters()
|
||||
{}
|
||||
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
NodeParameters::set_parameters(
|
||||
RCLCPP_LOCAL
|
||||
bool
|
||||
__lockless_has_parameter(
|
||||
const std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameters,
|
||||
const std::string & name)
|
||||
{
|
||||
return parameters.find(name) != parameters.end();
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
RCLCPP_LOCAL
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
__set_parameters_atomically_common(
|
||||
const std::vector<rclcpp::Parameter> & parameters,
|
||||
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameter_infos,
|
||||
OnParametersSetCallbackType on_set_parameters_callback)
|
||||
{
|
||||
// Call the user callback to see if the new value(s) are allowed.
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
result.successful = true;
|
||||
if (on_set_parameters_callback) {
|
||||
result = on_set_parameters_callback(parameters);
|
||||
}
|
||||
if (!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) {
|
||||
const std::string & name = parameters[i].get_name();
|
||||
parameter_infos[name].descriptor.name = parameters[i].get_name();
|
||||
parameter_infos[name].descriptor.type = parameters[i].get_type();
|
||||
parameter_infos[name].value = parameters[i].get_parameter_value();
|
||||
}
|
||||
}
|
||||
|
||||
// Either way, return the result.
|
||||
return result;
|
||||
}
|
||||
|
||||
RCLCPP_LOCAL
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
__declare_parameter_common(
|
||||
const std::string & name,
|
||||
const rclcpp::ParameterValue & default_value,
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
|
||||
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameters_out,
|
||||
const std::map<std::string, rclcpp::ParameterValue> & overrides,
|
||||
OnParametersSetCallbackType on_set_parameters_callback,
|
||||
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 overrides if available, otherwise use the default.
|
||||
const rclcpp::ParameterValue * initial_value = &default_value;
|
||||
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.
|
||||
std::vector<rclcpp::Parameter> parameter_wrappers {rclcpp::Parameter(name, *initial_value)};
|
||||
// This function also takes care of default vs initial value.
|
||||
auto result = __set_parameters_atomically_common(
|
||||
parameter_wrappers,
|
||||
parameter_infos,
|
||||
on_set_parameters_callback);
|
||||
|
||||
// Add declared parameters to storage.
|
||||
parameters_out[name] = parameter_infos.at(name);
|
||||
|
||||
// Extend the given parameter event, if valid.
|
||||
if (parameter_event_out) {
|
||||
parameter_event_out->new_parameters.push_back(parameter_wrappers[0].to_parameter_msg());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const rclcpp::ParameterValue &
|
||||
NodeParameters::declare_parameter(
|
||||
const std::string & name,
|
||||
const rclcpp::ParameterValue & default_value,
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
// TODO(sloretz) parameter name validation
|
||||
if (name.empty()) {
|
||||
throw rclcpp::exceptions::InvalidParametersException("parameter name must not be empty");
|
||||
}
|
||||
|
||||
// Error if this parameter has already been declared and is different
|
||||
if (__lockless_has_parameter(parameters_, name)) {
|
||||
throw rclcpp::exceptions::ParameterAlreadyDeclaredException(
|
||||
"parameter '" + name + "' has already been declared");
|
||||
}
|
||||
|
||||
rcl_interfaces::msg::ParameterEvent parameter_event;
|
||||
auto result = __declare_parameter_common(
|
||||
name,
|
||||
default_value,
|
||||
parameter_descriptor,
|
||||
parameters_,
|
||||
parameter_overrides_,
|
||||
on_parameters_set_callback_,
|
||||
¶meter_event);
|
||||
|
||||
// If it failed to be set, then throw an exception.
|
||||
if (!result.successful) {
|
||||
throw rclcpp::exceptions::InvalidParameterValueException(
|
||||
"parameter '" + name + "' could not be set: " + result.reason);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
void
|
||||
NodeParameters::undeclare_parameter(const std::string & name)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
auto parameter_info = parameters_.find(name);
|
||||
if (parameter_info == parameters_.end()) {
|
||||
throw rclcpp::exceptions::ParameterNotDeclaredException(
|
||||
"cannot undeclare parameter '" + name + "' which has not yet been declared");
|
||||
}
|
||||
|
||||
if (parameter_info->second.descriptor.read_only) {
|
||||
throw rclcpp::exceptions::ParameterImmutableException(
|
||||
"cannot undeclare parameter '" + name + "' because it is read-only");
|
||||
}
|
||||
|
||||
parameters_.erase(parameter_info);
|
||||
}
|
||||
|
||||
bool
|
||||
NodeParameters::has_parameter(const std::string & name) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
return __lockless_has_parameter(parameters_, name);
|
||||
}
|
||||
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
NodeParameters::set_parameters(const std::vector<rclcpp::Parameter> & parameters)
|
||||
{
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult> results;
|
||||
results.reserve(parameters.size());
|
||||
|
||||
for (const auto & p : parameters) {
|
||||
auto result = set_parameters_atomically({{p}});
|
||||
results.push_back(result);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
template<typename ParameterVectorType>
|
||||
auto
|
||||
__find_parameter_by_name(
|
||||
ParameterVectorType & parameters,
|
||||
const std::string & name)
|
||||
{
|
||||
return std::find_if(
|
||||
parameters.begin(),
|
||||
parameters.end(),
|
||||
[&](auto parameter) {return parameter.get_name() == name;});
|
||||
}
|
||||
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
NodeParameters::set_parameters_atomically(
|
||||
const std::vector<rclcpp::Parameter> & parameters)
|
||||
NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> & parameters)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::map<std::string, rclcpp::Parameter> tmp_map;
|
||||
auto parameter_event = std::make_shared<rcl_interfaces::msg::ParameterEvent>();
|
||||
|
||||
parameter_event->node = combined_name_;
|
||||
|
||||
// TODO(jacquelinekay): handle parameter constraints
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
if (parameters_callback_) {
|
||||
result = parameters_callback_(parameters);
|
||||
} else {
|
||||
result.successful = true;
|
||||
|
||||
// Check if any of the parameters are read-only, or if any parameters are not
|
||||
// declared.
|
||||
// If not declared, keep track of them in order to declare them later, when
|
||||
// undeclared parameters are allowed, and if they're not allowed, fail.
|
||||
std::vector<const rclcpp::Parameter *> parameters_to_be_declared;
|
||||
for (const auto & parameter : parameters) {
|
||||
const std::string & name = parameter.get_name();
|
||||
|
||||
// Check to make sure the parameter name is valid.
|
||||
if (name.empty()) {
|
||||
throw rclcpp::exceptions::InvalidParametersException("parameter name must not be empty");
|
||||
}
|
||||
|
||||
// Check to see if it is declared.
|
||||
auto parameter_info = parameters_.find(name);
|
||||
if (parameter_info == parameters_.end()) {
|
||||
// If not check to see if undeclared paramaters are allowed, ...
|
||||
if (allow_undeclared_) {
|
||||
// If so, mark the parameter to be declared for the user implicitly.
|
||||
parameters_to_be_declared.push_back(¶meter);
|
||||
// continue as it cannot be read-only, and because the declare will
|
||||
// implicitly set the parameter and parameter_infos is for setting only.
|
||||
continue;
|
||||
} else {
|
||||
// If not, then throw the exception as documented.
|
||||
throw rclcpp::exceptions::ParameterNotDeclaredException(
|
||||
"parameter '" + name + "' cannot be set because it was not declared");
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if it is read-only.
|
||||
if (parameter_info->second.descriptor.read_only) {
|
||||
result.successful = false;
|
||||
result.reason = "parameter '" + name + "' cannot be set because it is read-only";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Declare parameters into a temporary "staging area", incase one of the declares fail.
|
||||
// We will use the staged changes as input to the "set atomically" action.
|
||||
// We explicitly avoid calling the user callback here, so that it may be called once, with
|
||||
// all the other parameters to be set (already declared parameters).
|
||||
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> staged_parameter_changes;
|
||||
rcl_interfaces::msg::ParameterEvent parameter_event_msg;
|
||||
parameter_event_msg.node = combined_name_;
|
||||
for (auto parameter_to_be_declared : parameters_to_be_declared) {
|
||||
// This should not throw, because we validated the name and checked that
|
||||
// the parameter was not already declared.
|
||||
result = __declare_parameter_common(
|
||||
parameter_to_be_declared->get_name(),
|
||||
parameter_to_be_declared->get_parameter_value(),
|
||||
rcl_interfaces::msg::ParameterDescriptor(), // Implicit declare uses default descriptor.
|
||||
staged_parameter_changes,
|
||||
parameter_overrides_,
|
||||
nullptr, // callback is explicitly null, so that it is called only once, when setting below.
|
||||
¶meter_event_msg,
|
||||
false);
|
||||
if (!result.successful) {
|
||||
// Declare failed, return knowing that nothing was changed because the
|
||||
// staged changes were not applied.
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// If there were implicitly declared parameters, then we may need to copy the input parameters
|
||||
// and then assign the value that was selected after the declare (could be affected by the
|
||||
// initial parameter values).
|
||||
const std::vector<rclcpp::Parameter> * parameters_to_be_set = ¶meters;
|
||||
std::vector<rclcpp::Parameter> parameters_copy;
|
||||
if (0 != staged_parameter_changes.size()) { // If there were any implicitly declared parameters.
|
||||
bool any_initial_values_used = false;
|
||||
for (const auto & staged_parameter_change : staged_parameter_changes) {
|
||||
auto it = __find_parameter_by_name(parameters, staged_parameter_change.first);
|
||||
if (it->get_parameter_value() != staged_parameter_change.second.value) {
|
||||
// In this case, the value of the staged parameter differs from the
|
||||
// input from the user, and therefore we need to update things before setting.
|
||||
any_initial_values_used = true;
|
||||
// No need to search further since at least one initial value needs to be used.
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (any_initial_values_used) {
|
||||
parameters_copy = parameters;
|
||||
for (const auto & staged_parameter_change : staged_parameter_changes) {
|
||||
auto it = __find_parameter_by_name(parameters_copy, staged_parameter_change.first);
|
||||
*it = Parameter(staged_parameter_change.first, staged_parameter_change.second.value);
|
||||
}
|
||||
parameters_to_be_set = ¶meters_copy;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect parameters who will have had their type changed to
|
||||
// rclcpp::PARAMETER_NOT_SET so they can later be implicitly undeclared.
|
||||
std::vector<const rclcpp::Parameter *> parameters_to_be_undeclared;
|
||||
for (const auto & parameter : *parameters_to_be_set) {
|
||||
if (rclcpp::PARAMETER_NOT_SET == parameter.get_type()) {
|
||||
auto it = parameters_.find(parameter.get_name());
|
||||
if (it != parameters_.end() && rclcpp::PARAMETER_NOT_SET != it->second.value.get_type()) {
|
||||
parameters_to_be_undeclared.push_back(¶meter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the all of the parameters including the ones declared implicitly above.
|
||||
result = __set_parameters_atomically_common(
|
||||
// either the original parameters given by the user, or ones updated with initial values
|
||||
*parameters_to_be_set,
|
||||
// they are actually set on the official parameter storage
|
||||
parameters_,
|
||||
// this will get called once, with all the parameters to be set
|
||||
on_parameters_set_callback_);
|
||||
|
||||
// If not successful, then stop here.
|
||||
if (!result.successful) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (const auto & p : parameters) {
|
||||
if (p.get_type() == rclcpp::ParameterType::PARAMETER_NOT_SET) {
|
||||
if (parameters_.find(p.get_name()) != parameters_.end()) {
|
||||
// case: parameter was set before, and input is "NOT_SET"
|
||||
// therefore we will erase the parameter from parameters_ later
|
||||
parameter_event->deleted_parameters.push_back(p.to_parameter_msg());
|
||||
}
|
||||
} else {
|
||||
if (parameters_.find(p.get_name()) == parameters_.end()) {
|
||||
// case: parameter not set before, and input is something other than "NOT_SET"
|
||||
parameter_event->new_parameters.push_back(p.to_parameter_msg());
|
||||
} else {
|
||||
// case: parameter was set before, and input is something other than "NOT_SET"
|
||||
parameter_event->changed_parameters.push_back(p.to_parameter_msg());
|
||||
}
|
||||
tmp_map[p.get_name()] = p;
|
||||
}
|
||||
// If successful, then update the parameter infos from the implicitly declared parameter's.
|
||||
for (const auto & kv_pair : staged_parameter_changes) {
|
||||
// assumption: the parameter is already present in parameters_ due to the above "set"
|
||||
assert(__lockless_has_parameter(parameters_, kv_pair.first));
|
||||
// assumption: the value in parameters_ is the same as the value resulting from the declare
|
||||
assert(parameters_[kv_pair.first].value == kv_pair.second.value);
|
||||
// This assignment should not change the name, type, or value, but may
|
||||
// change other things from the ParameterInfo.
|
||||
parameters_[kv_pair.first] = kv_pair.second;
|
||||
}
|
||||
// std::map::insert will not overwrite elements, so we'll keep the new
|
||||
// ones and add only those that already exist in the Node's internal map
|
||||
tmp_map.insert(parameters_.begin(), parameters_.end());
|
||||
|
||||
// remove explicitly deleted parameters
|
||||
for (const auto & p : parameters) {
|
||||
if (p.get_type() == rclcpp::ParameterType::PARAMETER_NOT_SET) {
|
||||
tmp_map.erase(p.get_name());
|
||||
// Undeclare parameters that need to be.
|
||||
for (auto parameter_to_undeclare : parameters_to_be_undeclared) {
|
||||
auto it = parameters_.find(parameter_to_undeclare->get_name());
|
||||
// assumption: the parameter to be undeclared should be in the parameter infos map
|
||||
assert(it != parameters_.end());
|
||||
if (it != parameters_.end()) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
std::swap(tmp_map, parameters_);
|
||||
// Update the parameter event message for any parameters which were only set,
|
||||
// and not either declared or undeclared.
|
||||
for (const auto & parameter : *parameters_to_be_set) {
|
||||
if (staged_parameter_changes.find(parameter.get_name()) != staged_parameter_changes.end()) {
|
||||
// This parameter was declared.
|
||||
continue;
|
||||
}
|
||||
auto it = std::find_if(
|
||||
parameters_to_be_undeclared.begin(),
|
||||
parameters_to_be_undeclared.end(),
|
||||
[¶meter](const auto & p) {return p->get_name() == parameter.get_name();});
|
||||
if (it != parameters_to_be_undeclared.end()) {
|
||||
// This parameter was undeclared (deleted).
|
||||
continue;
|
||||
}
|
||||
// This parameter was neither declared nor undeclared.
|
||||
parameter_event_msg.changed_parameters.push_back(parameter.to_parameter_msg());
|
||||
}
|
||||
|
||||
// events_publisher_ may be nullptr if it was disabled in constructor
|
||||
// Publish if events_publisher_ is not nullptr, which may be if disabled in the constructor.
|
||||
if (nullptr != events_publisher_) {
|
||||
parameter_event->stamp = node_clock_->get_clock()->now();
|
||||
events_publisher_->publish(parameter_event);
|
||||
parameter_event_msg.stamp = node_clock_->get_clock()->now();
|
||||
events_publisher_->publish(parameter_event_msg);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -251,14 +643,19 @@ NodeParameters::get_parameters(const std::vector<std::string> & names) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::vector<rclcpp::Parameter> results;
|
||||
results.reserve(names.size());
|
||||
|
||||
for (auto & name : names) {
|
||||
if (std::any_of(parameters_.cbegin(), parameters_.cend(),
|
||||
[&name](const std::pair<std::string, rclcpp::Parameter> & kv) {
|
||||
return name == kv.first;
|
||||
}))
|
||||
{
|
||||
results.push_back(parameters_.at(name));
|
||||
auto found_parameter = parameters_.find(name);
|
||||
if (found_parameter != parameters_.cend()) {
|
||||
// found
|
||||
results.emplace_back(name, found_parameter->second.value);
|
||||
} else if (this->allow_undeclared_) {
|
||||
// not found, but undeclared allowed
|
||||
results.emplace_back(name, rclcpp::ParameterValue());
|
||||
} else {
|
||||
// not found, and undeclared are not allowed
|
||||
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
@@ -271,8 +668,10 @@ NodeParameters::get_parameter(const std::string & name) const
|
||||
|
||||
if (get_parameter(name, parameter)) {
|
||||
return parameter;
|
||||
} else if (this->allow_undeclared_) {
|
||||
return parameter;
|
||||
} else {
|
||||
throw std::out_of_range("Parameter '" + name + "' not set");
|
||||
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,8 +682,12 @@ NodeParameters::get_parameter(
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
if (parameters_.count(name)) {
|
||||
parameter = parameters_.at(name);
|
||||
auto param_iter = parameters_.find(name);
|
||||
if (
|
||||
parameters_.end() != param_iter &&
|
||||
param_iter->second.value.get_type() != rclcpp::ParameterType::PARAMETER_NOT_SET)
|
||||
{
|
||||
parameter = {name, param_iter->second.value};
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -296,15 +699,15 @@ NodeParameters::get_parameters_by_prefix(
|
||||
const std::string & prefix,
|
||||
std::map<std::string, rclcpp::Parameter> & parameters) const
|
||||
{
|
||||
std::string prefix_with_dot = prefix + ".";
|
||||
bool ret = false;
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
std::string prefix_with_dot = prefix.empty() ? prefix : prefix + ".";
|
||||
bool ret = false;
|
||||
|
||||
for (const auto & param : parameters_) {
|
||||
if (param.first.find(prefix_with_dot) == 0 && param.first.length() > prefix_with_dot.length()) {
|
||||
// Found one!
|
||||
parameters[param.first.substr(prefix_with_dot.length())] = param.second;
|
||||
parameters[param.first.substr(prefix_with_dot.length())] = rclcpp::Parameter(param.second);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
@@ -317,17 +720,26 @@ NodeParameters::describe_parameters(const std::vector<std::string> & names) cons
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::vector<rcl_interfaces::msg::ParameterDescriptor> results;
|
||||
for (auto & kv : parameters_) {
|
||||
if (std::any_of(names.cbegin(), names.cend(), [&kv](const std::string & name) {
|
||||
return name == kv.first;
|
||||
}))
|
||||
{
|
||||
rcl_interfaces::msg::ParameterDescriptor parameter_descriptor;
|
||||
parameter_descriptor.name = kv.first;
|
||||
parameter_descriptor.type = kv.second.get_type();
|
||||
results.push_back(parameter_descriptor);
|
||||
results.reserve(names.size());
|
||||
|
||||
for (const auto & name : names) {
|
||||
auto it = parameters_.find(name);
|
||||
if (it != parameters_.cend()) {
|
||||
results.push_back(it->second.descriptor);
|
||||
} else if (allow_undeclared_) {
|
||||
// parameter not found, but undeclared allowed, so return empty
|
||||
rcl_interfaces::msg::ParameterDescriptor default_description;
|
||||
default_description.name = name;
|
||||
results.push_back(default_description);
|
||||
} else {
|
||||
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
|
||||
}
|
||||
}
|
||||
|
||||
if (results.size() != names.size()) {
|
||||
throw std::runtime_error("results and names unexpectedly different sizes");
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -336,16 +748,24 @@ NodeParameters::get_parameter_types(const std::vector<std::string> & names) cons
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::vector<uint8_t> results;
|
||||
for (auto & kv : parameters_) {
|
||||
if (std::any_of(names.cbegin(), names.cend(), [&kv](const std::string & name) {
|
||||
return name == kv.first;
|
||||
}))
|
||||
{
|
||||
results.push_back(kv.second.get_type());
|
||||
} else {
|
||||
results.reserve(names.size());
|
||||
|
||||
for (const auto & name : names) {
|
||||
auto it = parameters_.find(name);
|
||||
if (it != parameters_.cend()) {
|
||||
results.push_back(it->second.value.get_type());
|
||||
} else if (allow_undeclared_) {
|
||||
// parameter not found, but undeclared allowed, so return not set
|
||||
results.push_back(rcl_interfaces::msg::ParameterType::PARAMETER_NOT_SET);
|
||||
} else {
|
||||
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
|
||||
}
|
||||
}
|
||||
|
||||
if (results.size() != names.size()) {
|
||||
throw std::runtime_error("results and names unexpectedly different sizes");
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -391,12 +811,39 @@ NodeParameters::list_parameters(const std::vector<std::string> & prefixes, uint6
|
||||
return result;
|
||||
}
|
||||
|
||||
NodeParameters::OnParametersSetCallbackType
|
||||
NodeParameters::set_on_parameters_set_callback(OnParametersSetCallbackType callback)
|
||||
{
|
||||
auto existing_callback = on_parameters_set_callback_;
|
||||
on_parameters_set_callback_ = callback;
|
||||
return existing_callback;
|
||||
}
|
||||
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
void
|
||||
NodeParameters::register_param_change_callback(ParametersCallbackFunction callback)
|
||||
{
|
||||
if (parameters_callback_) {
|
||||
RCUTILS_LOG_WARN("param_change_callback already registered, "
|
||||
"overwriting previous callback");
|
||||
if (on_parameters_set_callback_) {
|
||||
RCLCPP_WARN(
|
||||
node_logging_->get_logger(),
|
||||
"on_parameters_set_callback already registered, overwriting previous callback");
|
||||
}
|
||||
parameters_callback_ = callback;
|
||||
on_parameters_set_callback_ = callback;
|
||||
}
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic pop
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
const std::map<std::string, rclcpp::ParameterValue> &
|
||||
NodeParameters::get_parameter_overrides() const
|
||||
{
|
||||
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,87 +146,129 @@ 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;
|
||||
}
|
||||
|
||||
const bool &
|
||||
bool
|
||||
NodeOptions::use_global_arguments() const
|
||||
{
|
||||
return this->node_options_->use_global_arguments;
|
||||
return this->use_global_arguments_;
|
||||
}
|
||||
|
||||
NodeOptions &
|
||||
NodeOptions::use_global_arguments(const bool & use_global_arguments)
|
||||
NodeOptions::use_global_arguments(bool use_global_arguments)
|
||||
{
|
||||
this->node_options_.reset(); // reset node options to make it be recreated on next access.
|
||||
this->use_global_arguments_ = use_global_arguments;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const bool &
|
||||
bool
|
||||
NodeOptions::use_intra_process_comms() const
|
||||
{
|
||||
return this->use_intra_process_comms_;
|
||||
}
|
||||
|
||||
NodeOptions &
|
||||
NodeOptions::use_intra_process_comms(const bool & use_intra_process_comms)
|
||||
NodeOptions::use_intra_process_comms(bool use_intra_process_comms)
|
||||
{
|
||||
this->use_intra_process_comms_ = use_intra_process_comms;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const bool &
|
||||
bool
|
||||
NodeOptions::start_parameter_services() const
|
||||
{
|
||||
return this->start_parameter_services_;
|
||||
}
|
||||
|
||||
NodeOptions &
|
||||
NodeOptions::start_parameter_services(const bool & start_parameter_services)
|
||||
NodeOptions::start_parameter_services(bool start_parameter_services)
|
||||
{
|
||||
this->start_parameter_services_ = start_parameter_services;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const bool &
|
||||
bool
|
||||
NodeOptions::start_parameter_event_publisher() const
|
||||
{
|
||||
return this->start_parameter_event_publisher_;
|
||||
}
|
||||
|
||||
NodeOptions &
|
||||
NodeOptions::start_parameter_event_publisher(const bool & start_parameter_event_publisher)
|
||||
NodeOptions::start_parameter_event_publisher(bool start_parameter_event_publisher)
|
||||
{
|
||||
this->start_parameter_event_publisher_ = start_parameter_event_publisher;
|
||||
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;
|
||||
}
|
||||
|
||||
bool
|
||||
NodeOptions::allow_undeclared_parameters() const
|
||||
{
|
||||
return this->allow_undeclared_parameters_;
|
||||
}
|
||||
|
||||
NodeOptions &
|
||||
NodeOptions::allow_undeclared_parameters(bool allow_undeclared_parameters)
|
||||
{
|
||||
this->allow_undeclared_parameters_ = allow_undeclared_parameters;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
NodeOptions::automatically_declare_parameters_from_overrides() const
|
||||
{
|
||||
return this->automatically_declare_parameters_from_overrides_;
|
||||
}
|
||||
|
||||
NodeOptions &
|
||||
NodeOptions::automatically_declare_parameters_from_overrides(
|
||||
bool automatically_declare_parameters_from_overrides)
|
||||
{
|
||||
this->automatically_declare_parameters_from_overrides_ =
|
||||
automatically_declare_parameters_from_overrides;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -248,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
|
||||
|
||||
@@ -12,12 +12,24 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "rclcpp/parameter.hpp"
|
||||
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/parameter.hpp"
|
||||
// When compiling this file, Windows produces a deprecation warning for the
|
||||
// deprecated function prototype of NodeParameters::register_param_change_callback().
|
||||
// Other compilers do not.
|
||||
#if defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
#include "rclcpp/node_interfaces/node_parameters.hpp"
|
||||
#if defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
#include "rclcpp/utilities.hpp"
|
||||
|
||||
using rclcpp::ParameterType;
|
||||
@@ -28,11 +40,33 @@ Parameter::Parameter()
|
||||
{
|
||||
}
|
||||
|
||||
Parameter::Parameter(const std::string & name)
|
||||
: name_(name), value_()
|
||||
{
|
||||
}
|
||||
|
||||
Parameter::Parameter(const std::string & name, const rclcpp::ParameterValue & value)
|
||||
: name_(name), value_(value)
|
||||
{
|
||||
}
|
||||
|
||||
Parameter::Parameter(const rclcpp::node_interfaces::ParameterInfo & parameter_info)
|
||||
: Parameter(parameter_info.descriptor.name, parameter_info.value)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Parameter::operator==(const Parameter & rhs) const
|
||||
{
|
||||
return this->name_ == rhs.name_ && this->value_ == rhs.value_;
|
||||
}
|
||||
|
||||
bool
|
||||
Parameter::operator!=(const Parameter & rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
ParameterType
|
||||
Parameter::get_type() const
|
||||
{
|
||||
@@ -57,6 +91,12 @@ Parameter::get_value_message() const
|
||||
return value_.to_value_msg();
|
||||
}
|
||||
|
||||
const rclcpp::ParameterValue &
|
||||
Parameter::get_parameter_value() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
bool
|
||||
Parameter::as_bool() const
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -227,3 +227,15 @@ ParameterValue::to_value_msg() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
bool
|
||||
ParameterValue::operator==(const ParameterValue & rhs) const
|
||||
{
|
||||
return this->value_ == rhs.value_;
|
||||
}
|
||||
|
||||
bool
|
||||
ParameterValue::operator!=(const ParameterValue & rhs) const
|
||||
{
|
||||
return this->value_ != rhs.value_;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -78,39 +79,42 @@ void TimeSource::attachNode(
|
||||
|
||||
logger_ = node_logging_->get_logger();
|
||||
|
||||
rclcpp::Parameter use_sim_time_param;
|
||||
if (node_parameters_->get_parameter("use_sim_time", use_sim_time_param)) {
|
||||
if (use_sim_time_param.get_type() == rclcpp::PARAMETER_BOOL) {
|
||||
if (use_sim_time_param.get_value<bool>() == true) {
|
||||
parameter_state_ = SET_TRUE;
|
||||
enable_ros_time();
|
||||
create_clock_sub();
|
||||
}
|
||||
} else {
|
||||
RCLCPP_ERROR(logger_, "Invalid type for parameter 'use_sim_time' %s should be bool",
|
||||
use_sim_time_param.get_type_name().c_str());
|
||||
// Though this defaults to false, it can be overridden by initial parameter values for the node,
|
||||
// which may be given by the user at the node's construction or even by command-line arguments.
|
||||
rclcpp::ParameterValue use_sim_time_param;
|
||||
const char * use_sim_time_name = "use_sim_time";
|
||||
if (!node_parameters_->has_parameter(use_sim_time_name)) {
|
||||
use_sim_time_param = node_parameters_->declare_parameter(
|
||||
use_sim_time_name,
|
||||
rclcpp::ParameterValue(false),
|
||||
rcl_interfaces::msg::ParameterDescriptor());
|
||||
} else {
|
||||
use_sim_time_param = node_parameters_->get_parameter(use_sim_time_name).get_parameter_value();
|
||||
}
|
||||
if (use_sim_time_param.get_type() == rclcpp::PARAMETER_BOOL) {
|
||||
if (use_sim_time_param.get<bool>()) {
|
||||
parameter_state_ = SET_TRUE;
|
||||
enable_ros_time();
|
||||
create_clock_sub();
|
||||
}
|
||||
} else {
|
||||
RCLCPP_DEBUG(logger_, "'use_sim_time' parameter not set, using wall time by default.");
|
||||
// TODO(wjwwood): use set_on_parameters_set_callback to catch the type mismatch,
|
||||
// before the use_sim_time parameter can ever be set to an invalid value
|
||||
RCLCPP_ERROR(logger_, "Invalid type '%s' for parameter 'use_sim_time', should be 'bool'",
|
||||
rclcpp::to_string(use_sim_time_param.get_type()).c_str());
|
||||
}
|
||||
|
||||
// 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();
|
||||
@@ -199,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()
|
||||
@@ -229,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) {
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/contexts/default_context.hpp"
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
|
||||
#include "rcutils/logging_macros.h"
|
||||
|
||||
using rclcpp::TimerBase;
|
||||
@@ -75,6 +77,17 @@ TimerBase::cancel()
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
TimerBase::is_canceled()
|
||||
{
|
||||
bool is_canceled = false;
|
||||
rcl_ret_t ret = rcl_timer_is_canceled(timer_handle_.get(), &is_canceled);
|
||||
if (ret != RCL_RET_OK) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret, "Couldn't get timer cancelled state");
|
||||
}
|
||||
return is_canceled;
|
||||
}
|
||||
|
||||
void
|
||||
TimerBase::reset()
|
||||
{
|
||||
|
||||
@@ -24,45 +24,48 @@
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/rcl.h"
|
||||
|
||||
void
|
||||
rclcpp::init(int argc, char const * const argv[], const rclcpp::InitOptions & init_options)
|
||||
namespace rclcpp
|
||||
{
|
||||
using rclcpp::contexts::default_context::get_global_default_context;
|
||||
|
||||
void
|
||||
init(int argc, char const * const argv[], const InitOptions & init_options)
|
||||
{
|
||||
using contexts::default_context::get_global_default_context;
|
||||
get_global_default_context()->init(argc, argv, init_options);
|
||||
// Install the signal handlers.
|
||||
rclcpp::install_signal_handlers();
|
||||
install_signal_handlers();
|
||||
}
|
||||
|
||||
bool
|
||||
rclcpp::install_signal_handlers()
|
||||
install_signal_handlers()
|
||||
{
|
||||
return rclcpp::SignalHandler::get_global_signal_handler().install();
|
||||
return SignalHandler::get_global_signal_handler().install();
|
||||
}
|
||||
|
||||
bool
|
||||
rclcpp::signal_handlers_installed()
|
||||
signal_handlers_installed()
|
||||
{
|
||||
return rclcpp::SignalHandler::get_global_signal_handler().is_installed();
|
||||
return SignalHandler::get_global_signal_handler().is_installed();
|
||||
}
|
||||
|
||||
bool
|
||||
rclcpp::uninstall_signal_handlers()
|
||||
uninstall_signal_handlers()
|
||||
{
|
||||
return rclcpp::SignalHandler::get_global_signal_handler().uninstall();
|
||||
return SignalHandler::get_global_signal_handler().uninstall();
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
rclcpp::init_and_remove_ros_arguments(
|
||||
init_and_remove_ros_arguments(
|
||||
int argc,
|
||||
char const * const argv[],
|
||||
const rclcpp::InitOptions & init_options)
|
||||
const InitOptions & init_options)
|
||||
{
|
||||
rclcpp::init(argc, argv, init_options);
|
||||
return rclcpp::remove_ros_arguments(argc, argv);
|
||||
init(argc, argv, init_options);
|
||||
return remove_ros_arguments(argc, argv);
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
rclcpp::remove_ros_arguments(int argc, char const * const argv[])
|
||||
remove_ros_arguments(int argc, char const * const argv[])
|
||||
{
|
||||
rcl_allocator_t alloc = rcl_get_default_allocator();
|
||||
rcl_arguments_t parsed_args = rcl_get_zero_initialized_arguments();
|
||||
@@ -71,7 +74,7 @@ rclcpp::remove_ros_arguments(int argc, char const * const argv[])
|
||||
|
||||
ret = rcl_parse_arguments(argc, argv, alloc, &parsed_args);
|
||||
if (RCL_RET_OK != ret) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to parse arguments");
|
||||
exceptions::throw_from_rcl_error(ret, "failed to parse arguments");
|
||||
}
|
||||
|
||||
int nonros_argc = 0;
|
||||
@@ -84,9 +87,9 @@ rclcpp::remove_ros_arguments(int argc, char const * const argv[])
|
||||
&nonros_argc,
|
||||
&nonros_argv);
|
||||
|
||||
if (RCL_RET_OK != ret) {
|
||||
if (RCL_RET_OK != ret || nonros_argc < 0) {
|
||||
// Not using throw_from_rcl_error, because we may need to append deallocation failures.
|
||||
rclcpp::exceptions::RCLErrorBase base_exc(ret, rcl_get_error_state());
|
||||
exceptions::RCLErrorBase base_exc(ret, rcl_get_error_state());
|
||||
rcl_reset_error();
|
||||
if (NULL != nonros_argv) {
|
||||
alloc.deallocate(nonros_argv, alloc.state);
|
||||
@@ -97,13 +100,12 @@ rclcpp::remove_ros_arguments(int argc, char const * const argv[])
|
||||
rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
}
|
||||
throw rclcpp::exceptions::RCLError(base_exc, "");
|
||||
throw exceptions::RCLError(base_exc, "");
|
||||
}
|
||||
|
||||
std::vector<std::string> return_arguments;
|
||||
return_arguments.resize(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]);
|
||||
}
|
||||
|
||||
@@ -113,7 +115,7 @@ rclcpp::remove_ros_arguments(int argc, char const * const argv[])
|
||||
|
||||
ret = rcl_arguments_fini(&parsed_args);
|
||||
if (RCL_RET_OK != ret) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(
|
||||
exceptions::throw_from_rcl_error(
|
||||
ret, "failed to cleanup parsed arguments, leaking memory");
|
||||
}
|
||||
|
||||
@@ -121,9 +123,9 @@ rclcpp::remove_ros_arguments(int argc, char const * const argv[])
|
||||
}
|
||||
|
||||
bool
|
||||
rclcpp::ok(rclcpp::Context::SharedPtr context)
|
||||
ok(Context::SharedPtr context)
|
||||
{
|
||||
using rclcpp::contexts::default_context::get_global_default_context;
|
||||
using contexts::default_context::get_global_default_context;
|
||||
if (nullptr == context) {
|
||||
context = get_global_default_context();
|
||||
}
|
||||
@@ -131,30 +133,30 @@ rclcpp::ok(rclcpp::Context::SharedPtr context)
|
||||
}
|
||||
|
||||
bool
|
||||
rclcpp::is_initialized(rclcpp::Context::SharedPtr context)
|
||||
is_initialized(Context::SharedPtr context)
|
||||
{
|
||||
return rclcpp::ok(context);
|
||||
return ok(context);
|
||||
}
|
||||
|
||||
bool
|
||||
rclcpp::shutdown(rclcpp::Context::SharedPtr context, const std::string & reason)
|
||||
shutdown(Context::SharedPtr context, const std::string & reason)
|
||||
{
|
||||
using rclcpp::contexts::default_context::get_global_default_context;
|
||||
using contexts::default_context::get_global_default_context;
|
||||
auto default_context = get_global_default_context();
|
||||
if (nullptr == context) {
|
||||
context = default_context;
|
||||
}
|
||||
bool ret = context->shutdown(reason);
|
||||
if (context == default_context) {
|
||||
rclcpp::uninstall_signal_handlers();
|
||||
uninstall_signal_handlers();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
rclcpp::on_shutdown(std::function<void()> callback, rclcpp::Context::SharedPtr context)
|
||||
on_shutdown(std::function<void()> callback, Context::SharedPtr context)
|
||||
{
|
||||
using rclcpp::contexts::default_context::get_global_default_context;
|
||||
using contexts::default_context::get_global_default_context;
|
||||
if (nullptr == context) {
|
||||
context = get_global_default_context();
|
||||
}
|
||||
@@ -162,9 +164,9 @@ rclcpp::on_shutdown(std::function<void()> callback, rclcpp::Context::SharedPtr c
|
||||
}
|
||||
|
||||
bool
|
||||
rclcpp::sleep_for(const std::chrono::nanoseconds & nanoseconds, rclcpp::Context::SharedPtr context)
|
||||
sleep_for(const std::chrono::nanoseconds & nanoseconds, Context::SharedPtr context)
|
||||
{
|
||||
using rclcpp::contexts::default_context::get_global_default_context;
|
||||
using contexts::default_context::get_global_default_context;
|
||||
if (nullptr == context) {
|
||||
context = get_global_default_context();
|
||||
}
|
||||
@@ -172,13 +174,15 @@ rclcpp::sleep_for(const std::chrono::nanoseconds & nanoseconds, rclcpp::Context:
|
||||
}
|
||||
|
||||
const char *
|
||||
rclcpp::get_c_string(const char * string_in)
|
||||
get_c_string(const char * string_in)
|
||||
{
|
||||
return string_in;
|
||||
}
|
||||
|
||||
const char *
|
||||
rclcpp::get_c_string(const std::string & string_in)
|
||||
get_c_string(const std::string & string_in)
|
||||
{
|
||||
return string_in.c_str();
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
TEST(test_local_parameters, set_parameter_if_not_set) {
|
||||
auto node = rclcpp::Node::make_shared("test_local_parameters_set_parameter_if_not_set");
|
||||
auto node = rclcpp::Node::make_shared(
|
||||
"test_local_parameters_set_parameter_if_not_set",
|
||||
rclcpp::NodeOptions().allow_undeclared_parameters(true));
|
||||
|
||||
{
|
||||
// try to set a map of parameters
|
||||
@@ -29,7 +31,19 @@ TEST(test_local_parameters, set_parameter_if_not_set) {
|
||||
{"x", 0.5},
|
||||
{"y", 1.0},
|
||||
};
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
node->set_parameters_if_not_set("bar", bar_map);
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic pop
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
double bar_x_value;
|
||||
ASSERT_TRUE(node->get_parameter("bar.x", bar_x_value));
|
||||
EXPECT_EQ(bar_x_value, 0.5);
|
||||
@@ -51,8 +65,20 @@ TEST(test_local_parameters, set_parameter_if_not_set) {
|
||||
|
||||
{
|
||||
// set parameters for a map with different types, then try to get them back as a map
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
node->set_parameter_if_not_set("baz.x", 1.0);
|
||||
node->set_parameter_if_not_set("baz.y", "hello");
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic pop
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
std::map<std::string, double> baz_map;
|
||||
EXPECT_THROW(node->get_parameters("baz", baz_map), rclcpp::ParameterTypeException);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user