Compare commits

..

20 Commits

Author SHA1 Message Date
Michael Jeronimo
8fb32de707 Add a function to get all parameter values from a parameter event
Signed-off-by: Michael Jeronimo <michael.jeronimo@openrobotics.org>
2020-11-30 11:05:25 -08:00
Michael Jeronimo
b3b683f469 Remove a stray debug trace
Signed-off-by: Michael Jeronimo <michael.jeronimo@openrobotics.org>
2020-11-30 11:05:25 -08:00
Michael Jeronimo
e41f75c05f Remove some unneeded code
Signed-off-by: Michael Jeronimo <michael.jeronimo@openrobotics.org>
2020-11-30 11:05:25 -08:00
Michael Jeronimo
36e0190c27 Get rid of a few compiler warnings; add test to build
Signed-off-by: Michael Jeronimo <michael.jeronimo@openrobotics.org>
2020-11-30 11:05:25 -08:00
bpwilcox
f36035097f address feedback: replace ParameterEventsFilter dependency, fix copyright, add get_node_logging_interface, modify constructor
Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>
2020-11-30 11:05:25 -08:00
bpwilcox
e4bc1d8968 address feedback: move HandleCompare, test exceptions, reference code source
Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>
2020-11-30 11:05:25 -08:00
bpwilcox
0d5d75c9a2 update utility function description
Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>
2020-11-30 11:05:25 -08:00
bpwilcox
255943465d use get_child for parameter event subscriber logger
Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>
2020-11-30 11:05:25 -08:00
bpwilcox
9cc41c76c1 support multiple parameter event callbacks
Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>
2020-11-30 11:05:25 -08:00
bpwilcox
7c19dbb408 use absolute parameter event topic for parameter event subscriber
Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>
2020-11-30 11:05:25 -08:00
bpwilcox
921d2b4192 map parameters to list of callbacks
functions to remove parameter callbacks

add functions to remove event callbacks, remove subscriptions, allow subscribing event callback to many namespaces, additional test coverage

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>
2020-11-30 11:05:25 -08:00
bpwilcox
12329bf79c address feedback part 1: static get_parameter method, remove register_parameter_update, mutex for thread-safety
Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>
2020-11-30 11:05:25 -08:00
bpwilcox
f67d8298b2 add RCLCPP_PUBLIC macro
Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>
2020-11-30 11:05:25 -08:00
bpwilcox
a010d2dd15 address feedback (wjwwood) part 1
Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

use const string & for node name

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>
2020-11-30 11:05:25 -08:00
bpwilcox
f1893273f5 use unordered map with string pair, add test for different nodes same parameter, address feedback
Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>
2020-11-30 11:05:25 -08:00
bpwilcox
884a2d8ad8 pass rclcpp::Parameter object to callback, rename functions, get param from event
Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>
2020-11-30 11:05:25 -08:00
bpwilcox
72817ab1f2 add try-catch and warning around getting parameter value
Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>
2020-11-30 11:05:25 -08:00
bpwilcox
cdf4156bbe fix lint and uncrustify issues
Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>
2020-11-30 11:05:25 -08:00
bpwilcox
3246e349d3 test improvements, path name fixes, and more documentation
Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>
2020-11-30 11:05:25 -08:00
bpwilcox
6473041f1c add ParameterEventsSubscriber class and tests
Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>
2020-11-30 11:05:25 -08:00
177 changed files with 2078 additions and 8724 deletions

View File

@@ -12,6 +12,6 @@ Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) fo
### Examples
The ROS 2 tutorials [Writing a simple publisher and subscriber](https://docs.ros.org/en/rolling/Tutorials/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html).
and [Writing a simple service and client](https://docs.ros.org/en/rolling/Tutorials/Writing-A-Simple-Cpp-Service-And-Client.html)
The ROS 2 tutorials [Writing a simple publisher and subscriber](https://index.ros.org/doc/ros2/Tutorials/Writing-A-Simple-Cpp-Publisher-And-Subscriber/)
and [Writing a simple service and client](https://index.ros.org/doc/ros2/Tutorials/Writing-A-Simple-Cpp-Service-And-Client/)
contain some examples of rclcpp APIs in use.

View File

@@ -2,146 +2,6 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9.1.0 (2021-05-20)
------------------
* Allow declaring uninitialized statically typed parameters. (`#1673 <https://github.com/ros2/rclcpp/issues/1673>`_) (`#1681 <https://github.com/ros2/rclcpp/issues/1681>`_)
* [service] Don't use a weak_ptr to avoid leaking. (`#1668 <https://github.com/ros2/rclcpp/issues/1668>`_) (`#1670 <https://github.com/ros2/rclcpp/issues/1670>`_)
* Contributors: Jacob Perron, Ivan Santiago Paunovic
9.0.3 (2021-05-10)
------------------
* Use OnShutdown callback handle instead of OnShutdown callback (`#1639 <https://github.com/ros2/rclcpp/issues/1639>`_) (`#1650 <https://github.com/ros2/rclcpp/issues/1650>`_)
* use dynamic_pointer_cast to detect allocator mismatch in intra process manager (`#1643 <https://github.com/ros2/rclcpp/issues/1643>`_) (`#1644 <https://github.com/ros2/rclcpp/issues/1644>`_)
* Increase cppcheck timeout to 500s (`#1634 <https://github.com/ros2/rclcpp/issues/1634>`_)
* Clarify node parameters docs (`#1631 <https://github.com/ros2/rclcpp/issues/1631>`_)
* Contributors: Barry Xu, Jacob Perron, Michel Hidalgo, Shane Loretz, William Woodall
9.0.2 (2021-04-14)
------------------
* Avoid returning loan when none was obtained. (`#1629 <https://github.com/ros2/rclcpp/issues/1629>`_)
* Use a different implementation of mutex two priorities (`#1628 <https://github.com/ros2/rclcpp/issues/1628>`_)
* Do not test the value of the history policy when testing the get_publishers/subscriptions_info_by_topic() methods (`#1626 <https://github.com/ros2/rclcpp/issues/1626>`_)
* Check first parameter type and range before calling the user validation callbacks (`#1627 <https://github.com/ros2/rclcpp/issues/1627>`_)
* Contributors: Ivan Santiago Paunovic, Miguel Company
9.0.1 (2021-04-12)
------------------
* Restore test exception for Connext (`#1625 <https://github.com/ros2/rclcpp/issues/1625>`_)
* Fix race condition in TimeSource clock thread setup (`#1623 <https://github.com/ros2/rclcpp/issues/1623>`_)
* Contributors: Andrea Sorbini, Michel Hidalgo
9.0.0 (2021-04-06)
------------------
* remove deprecated code which was deprecated in foxy and should be removed in galactic (`#1622 <https://github.com/ros2/rclcpp/issues/1622>`_)
* Change index.ros.org -> docs.ros.org. (`#1620 <https://github.com/ros2/rclcpp/issues/1620>`_)
* Unique network flows (`#1496 <https://github.com/ros2/rclcpp/issues/1496>`_)
* Add spin_some support to the StaticSingleThreadedExecutor (`#1338 <https://github.com/ros2/rclcpp/issues/1338>`_)
* Add publishing instrumentation (`#1600 <https://github.com/ros2/rclcpp/issues/1600>`_)
* Create load_parameters and delete_parameters methods (`#1596 <https://github.com/ros2/rclcpp/issues/1596>`_)
* refactor AnySubscriptionCallback and add/deprecate callback signatures (`#1598 <https://github.com/ros2/rclcpp/issues/1598>`_)
* Add generic publisher and generic subscription for serialized messages (`#1452 <https://github.com/ros2/rclcpp/issues/1452>`_)
* use context from `node_base\_` for clock executor. (`#1617 <https://github.com/ros2/rclcpp/issues/1617>`_)
* updating quality declaration links (re: `ros2/docs.ros2.org#52 <https://github.com/ros2/docs.ros2.org/issues/52>`_) (`#1615 <https://github.com/ros2/rclcpp/issues/1615>`_)
* Contributors: Ananya Muddukrishna, BriceRenaudeau, Chris Lalancette, Christophe Bedard, Nikolai Morin, Tomoya Fujita, William Woodall, mauropasse, shonigmann
8.2.0 (2021-03-31)
------------------
* Initialize integers in test_parameter_event_handler.cpp to avoid undefined behavior (`#1609 <https://github.com/ros2/rclcpp/issues/1609>`_)
* Namespace tracetools C++ functions (`#1608 <https://github.com/ros2/rclcpp/issues/1608>`_)
* Revert "Namespace tracetools C++ functions (`#1603 <https://github.com/ros2/rclcpp/issues/1603>`_)" (`#1607 <https://github.com/ros2/rclcpp/issues/1607>`_)
* Namespace tracetools C++ functions (`#1603 <https://github.com/ros2/rclcpp/issues/1603>`_)
* Clock subscription callback group spins in its own thread (`#1556 <https://github.com/ros2/rclcpp/issues/1556>`_)
* Contributors: Chris Lalancette, Christophe Bedard, Ivan Santiago Paunovic, anaelle-sw
8.1.0 (2021-03-25)
------------------
* Remove rmw_connext_cpp references. (`#1595 <https://github.com/ros2/rclcpp/issues/1595>`_)
* Add API for checking QoS profile compatibility (`#1554 <https://github.com/ros2/rclcpp/issues/1554>`_)
* Document misuse of parameters callback (`#1590 <https://github.com/ros2/rclcpp/issues/1590>`_)
* use const auto & to iterate over parameters (`#1593 <https://github.com/ros2/rclcpp/issues/1593>`_)
* Contributors: Chris Lalancette, Jacob Perron, Karsten Knese
8.0.0 (2021-03-23)
------------------
* Guard against integer overflow in duration conversion (`#1584 <https://github.com/ros2/rclcpp/issues/1584>`_)
* Contributors: Jacob Perron
7.0.1 (2021-03-22)
------------------
* get_parameters service should return empty if undeclared parameters are allowed (`#1514 <https://github.com/ros2/rclcpp/issues/1514>`_)
* Made 'Context::shutdown_reason' function a const function (`#1578 <https://github.com/ros2/rclcpp/issues/1578>`_)
* Contributors: Tomoya Fujita, suab321321
7.0.0 (2021-03-18)
------------------
* Document design decisions that were made for statically typed parameters (`#1568 <https://github.com/ros2/rclcpp/issues/1568>`_)
* Fix doc typo in CallbackGroup constructor (`#1582 <https://github.com/ros2/rclcpp/issues/1582>`_)
* Enable qos parameter overrides for the /parameter_events topic (`#1532 <https://github.com/ros2/rclcpp/issues/1532>`_)
* Add support for rmw_connextdds (`#1574 <https://github.com/ros2/rclcpp/issues/1574>`_)
* Remove 'struct' from the rcl_time_jump_t. (`#1577 <https://github.com/ros2/rclcpp/issues/1577>`_)
* Add tests for declaring statically typed parameters when undeclared parameters are allowed (`#1575 <https://github.com/ros2/rclcpp/issues/1575>`_)
* Quiet clang memory leak warning on "DoNotOptimize". (`#1571 <https://github.com/ros2/rclcpp/issues/1571>`_)
* Add ParameterEventsSubscriber class (`#829 <https://github.com/ros2/rclcpp/issues/829>`_)
* When a parameter change is rejected, the parameters map shouldn't be updated. (`#1567 <https://github.com/ros2/rclcpp/pull/1567>`_)
* Fix when to throw the NoParameterOverrideProvided exception. (`#1567 <https://github.com/ros2/rclcpp/pull/1567>`_)
* Fix SEGV caused by order of destruction of Node sub-interfaces (`#1469 <https://github.com/ros2/rclcpp/issues/1469>`_)
* Fix benchmark test failure introduced in `#1522 <https://github.com/ros2/rclcpp/issues/1522>`_ (`#1564 <https://github.com/ros2/rclcpp/issues/1564>`_)
* Fix documented example in create_publisher (`#1558 <https://github.com/ros2/rclcpp/issues/1558>`_)
* Enforce static parameter types (`#1522 <https://github.com/ros2/rclcpp/issues/1522>`_)
* Allow timers to keep up the intended rate in MultiThreadedExecutor (`#1516 <https://github.com/ros2/rclcpp/issues/1516>`_)
* Fix UBSAN warnings in any_subscription_callback. (`#1551 <https://github.com/ros2/rclcpp/issues/1551>`_)
* Fix runtime error: reference binding to null pointer of type (`#1547 <https://github.com/ros2/rclcpp/issues/1547>`_)
* Contributors: Andrea Sorbini, Chris Lalancette, Colin MacKenzie, Ivan Santiago Paunovic, Jacob Perron, Steven! Ragnarök, bpwilcox, tomoya
6.3.1 (2021-02-08)
------------------
* Reference test resources directly from source tree (`#1543 <https://github.com/ros2/rclcpp/issues/1543>`_)
* clear statistics after window reset (`#1531 <https://github.com/ros2/rclcpp/issues/1531>`_) (`#1535 <https://github.com/ros2/rclcpp/issues/1535>`_)
* Fix a minor string error in the topic_statistics test. (`#1541 <https://github.com/ros2/rclcpp/issues/1541>`_)
* Avoid `Resource deadlock avoided` if use intra_process_comms (`#1530 <https://github.com/ros2/rclcpp/issues/1530>`_)
* Avoid an object copy in parameter_value.cpp. (`#1538 <https://github.com/ros2/rclcpp/issues/1538>`_)
* Assert that the publisher_list size is 1. (`#1537 <https://github.com/ros2/rclcpp/issues/1537>`_)
* Don't access objects after they have been std::move (`#1536 <https://github.com/ros2/rclcpp/issues/1536>`_)
* Update for checking correct variable (`#1534 <https://github.com/ros2/rclcpp/issues/1534>`_)
* Destroy msg extracted from LoanedMessage. (`#1305 <https://github.com/ros2/rclcpp/issues/1305>`_)
* Contributors: Chen Lihui, Chris Lalancette, Ivan Santiago Paunovic, Miaofei Mei, Scott K Logan, William Woodall, hsgwa
6.3.0 (2021-01-25)
------------------
* Add instrumentation for linking a timer to a node (`#1500 <https://github.com/ros2/rclcpp/issues/1500>`_)
* Fix error when using IPC with StaticSingleThreadExecutor (`#1520 <https://github.com/ros2/rclcpp/issues/1520>`_)
* Change to using unique_ptrs for DummyExecutor. (`#1517 <https://github.com/ros2/rclcpp/issues/1517>`_)
* Allow reconfiguring 'clock' topic qos (`#1512 <https://github.com/ros2/rclcpp/issues/1512>`_)
* Allow to add/remove nodes thread safely in rclcpp::Executor (`#1505 <https://github.com/ros2/rclcpp/issues/1505>`_)
* Call rclcpp::shutdown in test_node for clean shutdown on Windows (`#1515 <https://github.com/ros2/rclcpp/issues/1515>`_)
* Reapply "Add get_logging_directory method to rclcpp::Logger (`#1509 <https://github.com/ros2/rclcpp/issues/1509>`_)" (`#1513 <https://github.com/ros2/rclcpp/issues/1513>`_)
* use describe_parameters of parameter client for test (`#1499 <https://github.com/ros2/rclcpp/issues/1499>`_)
* Revert "Add get_logging_directory method to rclcpp::Logger (`#1509 <https://github.com/ros2/rclcpp/issues/1509>`_)" (`#1511 <https://github.com/ros2/rclcpp/issues/1511>`_)
* Add get_logging_directory method to rclcpp::Logger (`#1509 <https://github.com/ros2/rclcpp/issues/1509>`_)
* Contributors: Chris Lalancette, Christophe Bedard, Ivan Santiago Paunovic, eboasson, mauropasse, tomoya
6.2.0 (2021-01-08)
------------------
* Better documentation for the QoS class (`#1508 <https://github.com/ros2/rclcpp/issues/1508>`_)
* Modify excluding callback duration from topic statistics (`#1492 <https://github.com/ros2/rclcpp/issues/1492>`_)
* Make the test of graph users more robust. (`#1504 <https://github.com/ros2/rclcpp/issues/1504>`_)
* Make sure to wait for graph change events in test_node_graph. (`#1503 <https://github.com/ros2/rclcpp/issues/1503>`_)
* add timeout to SyncParametersClient methods (`#1493 <https://github.com/ros2/rclcpp/issues/1493>`_)
* Fix wrong test expectations (`#1497 <https://github.com/ros2/rclcpp/issues/1497>`_)
* Update create_publisher/subscription documentation, clarifying when a parameters interface is required (`#1494 <https://github.com/ros2/rclcpp/issues/1494>`_)
* Fix string literal warnings (`#1442 <https://github.com/ros2/rclcpp/issues/1442>`_)
* support describe_parameters methods to parameter client. (`#1453 <https://github.com/ros2/rclcpp/issues/1453>`_)
* Contributors: Audrow Nash, Chris Lalancette, Ivan Santiago Paunovic, Nikolai Morin, hsgwa, tomoya
6.1.0 (2020-12-10)
------------------
* Add getters to rclcpp::qos and rclcpp::Policy enum classes (`#1467 <https://github.com/ros2/rclcpp/issues/1467>`_)
* Change nullptr checks to use ASSERT_TRUE. (`#1486 <https://github.com/ros2/rclcpp/issues/1486>`_)
* Adjust logic around finding and erasing guard_condition (`#1474 <https://github.com/ros2/rclcpp/issues/1474>`_)
* Update QDs to QL 1 (`#1477 <https://github.com/ros2/rclcpp/issues/1477>`_)
* Add performance tests for parameter transport (`#1463 <https://github.com/ros2/rclcpp/issues/1463>`_)
* Contributors: Chris Lalancette, Ivan Santiago Paunovic, Scott K Logan, Stephen Brawner
6.0.0 (2020-11-18)
------------------
* Move ownership of shutdown_guard_condition to executors/graph_listener (`#1404 <https://github.com/ros2/rclcpp/issues/1404>`_)

View File

@@ -5,7 +5,6 @@ project(rclcpp)
find_package(Threads REQUIRED)
find_package(ament_cmake_ros REQUIRED)
find_package(ament_index_cpp REQUIRED)
find_package(builtin_interfaces REQUIRED)
find_package(libstatistics_collector REQUIRED)
find_package(rcl REQUIRED)
@@ -21,10 +20,9 @@ find_package(rosidl_typesupport_cpp REQUIRED)
find_package(statistics_msgs REQUIRED)
find_package(tracetools REQUIRED)
# TODO(wjwwood): remove this when gtest can build on its own, when using target_compile_features()
# Default to C++17
# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# About -Wno-sign-conversion: With Clang, -Wconversion implies -Wsign-conversion. There are a number of
@@ -41,8 +39,6 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/clock.cpp
src/rclcpp/context.cpp
src/rclcpp/contexts/default_context.cpp
src/rclcpp/detail/mutex_two_priorities.cpp
src/rclcpp/detail/resolve_parameter_overrides.cpp
src/rclcpp/detail/rmw_implementation_specific_payload.cpp
src/rclcpp/detail/rmw_implementation_specific_publisher_payload.cpp
src/rclcpp/detail/rmw_implementation_specific_subscription_payload.cpp
@@ -53,14 +49,12 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/executable_list.cpp
src/rclcpp/executor.cpp
src/rclcpp/executors.cpp
src/rclcpp/expand_topic_or_service_name.cpp
src/rclcpp/executors/multi_threaded_executor.cpp
src/rclcpp/executors/single_threaded_executor.cpp
src/rclcpp/executors/static_executor_entities_collector.cpp
src/rclcpp/executors/static_single_threaded_executor.cpp
src/rclcpp/expand_topic_or_service_name.cpp
src/rclcpp/future_return_code.cpp
src/rclcpp/generic_publisher.cpp
src/rclcpp/generic_subscription.cpp
src/rclcpp/graph_listener.cpp
src/rclcpp/guard_condition.cpp
src/rclcpp/init_options.cpp
@@ -70,8 +64,8 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/memory_strategies.cpp
src/rclcpp/memory_strategy.cpp
src/rclcpp/message_info.cpp
src/rclcpp/network_flow_endpoint.cpp
src/rclcpp/node.cpp
src/rclcpp/node_options.cpp
src/rclcpp/node_interfaces/node_base.cpp
src/rclcpp/node_interfaces/node_clock.cpp
src/rclcpp/node_interfaces/node_graph.cpp
@@ -82,14 +76,13 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/node_interfaces/node_timers.cpp
src/rclcpp/node_interfaces/node_topics.cpp
src/rclcpp/node_interfaces/node_waitables.cpp
src/rclcpp/node_options.cpp
src/rclcpp/parameter.cpp
src/rclcpp/parameter_value.cpp
src/rclcpp/parameter_client.cpp
src/rclcpp/parameter_event_handler.cpp
src/rclcpp/parameter_events_filter.cpp
src/rclcpp/parameter_events_subscriber.cpp
src/rclcpp/parameter_map.cpp
src/rclcpp/parameter_service.cpp
src/rclcpp/parameter_value.cpp
src/rclcpp/publisher_base.cpp
src/rclcpp/qos.cpp
src/rclcpp/qos_event.cpp
@@ -104,7 +97,6 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/time_source.cpp
src/rclcpp/timer.cpp
src/rclcpp/type_support.cpp
src/rclcpp/typesupport_helpers.cpp
src/rclcpp/utilities.cpp
src/rclcpp/wait_set_policies/detail/write_preferring_read_write_lock.cpp
src/rclcpp/waitable.cpp
@@ -176,12 +168,8 @@ foreach(interface_file ${interface_files})
include/rclcpp/node_interfaces/get_${interface_name}.hpp)
endforeach()
add_library(${PROJECT_NAME} ${${PROJECT_NAME}_SRCS})
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17)
# TODO(wjwwood): address all deprecation warnings and then remove this
if(WIN32)
target_compile_definitions(${PROJECT_NAME} PUBLIC "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS")
endif()
add_library(${PROJECT_NAME}
${${PROJECT_NAME}_SRCS})
target_include_directories(${PROJECT_NAME} PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
@@ -189,7 +177,6 @@ target_include_directories(${PROJECT_NAME} PUBLIC
target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT})
# specific order: dependents before dependencies
ament_target_dependencies(${PROJECT_NAME}
"ament_index_cpp"
"libstatistics_collector"
"rcl"
"rcl_yaml_param_parser"
@@ -220,7 +207,6 @@ ament_export_include_directories(include)
ament_export_libraries(${PROJECT_NAME})
ament_export_targets(${PROJECT_NAME})
ament_export_dependencies(ament_index_cpp)
ament_export_dependencies(libstatistics_collector)
ament_export_dependencies(rcl)
ament_export_dependencies(rcpputils)
@@ -247,8 +233,3 @@ install(
DIRECTORY include/ ${CMAKE_CURRENT_BINARY_DIR}/include/
DESTINATION include
)
if(TEST cppcheck)
# must set the property after ament_package()
set_tests_properties(cppcheck PROPERTIES TIMEOUT 500)
endif()

View File

@@ -4,13 +4,13 @@ This document is a declaration of software quality for the `rclcpp` package, bas
The package `rclcpp` claims to be in the **Quality Level 1** category when it is used with a **Quality Level 1** middleware.
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://www.ros.org/reps/rep-2004.html) of the ROS2 developer guide.
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#package-quality-categories) of the ROS2 developer guide.
## Version Policy [1]
### Version Scheme [1.i]
`rclcpp` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#versioning).
`rclcpp` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#versioning).
### Version Stability [1.ii]
@@ -39,11 +39,11 @@ Headers under the folder `detail` are not considered part of the public API and
## Change Control Process [2]
`rclcpp` follows the recommended guidelines for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process).
`rclcpp` follows the recommended guidelines for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process).
### Change Requests [2.i]
All changes will occur through a pull request, check [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process) for additional information.
All changes will occur through a pull request, check [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process) for additional information.
### Contributor Origin [2.ii]
@@ -51,7 +51,7 @@ This package uses DCO as its confirmation of contributor origin policy. More inf
### Peer Review Policy [2.iii]
All pull requests will be peer-reviewed, check [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process) for additional information.
All pull requests will be peer-reviewed, check [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process) for additional information.
### Continuous Integration [2.iv]
@@ -111,7 +111,7 @@ The tests aim to cover both typical usage and corner cases, but are quantified b
### Coverage [4.iii]
`rclcpp` follows the recommendations for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#code-coverage), and opts to use line coverage instead of branch coverage.
`rclcpp` follows the recommendations for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#code-coverage), and opts to use line coverage instead of branch coverage.
This includes:
@@ -121,13 +121,13 @@ This includes:
Changes are required to make a best effort to keep or increase coverage before being accepted, but decreases are allowed if properly justified and accepted by reviewers.
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastCompletedBuild/cobertura/src_ros2_rclcpp_rclcpp_src_rclcpp/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#note-on-coverage-runs).
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastCompletedBuild/cobertura/src_ros2_rclcpp_rclcpp_src_rclcpp/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://index.ros.org/doc/ros2/Contributing/ROS-2-On-boarding-Guide/#note-on-coverage-runs).
`rclcpp` has a line coverage `>= 95%`, which is calculated over all directories within `rclcpp` with the exception of the `experimental` directory.
### Performance [4.iv]
`rclcpp` follows the recommendations for performance testing of C/C++ code in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#performance), and opts to do performance analysis on each release rather than each change.
`rclcpp` follows the recommendations for performance testing of C/C++ code in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#performance), and opts to do performance analysis on each release rather than each change.
The performance tests of `rclcpp` are located in the [test/benchmark directory](https://github.com/ros2/rclcpp/tree/master/rclcpp/test/benchmark).
@@ -139,7 +139,7 @@ Changes that introduce regressions in performance must be adequately justified i
### Linters and Static Analysis [4.v]
`rclcpp` uses and passes all the ROS2 standard linters and static analysis tools for a C++ package as described in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#linters-and-static-analysis). Passing implies there are no linter/static errors when testing against CI of supported platforms.
`rclcpp` uses and passes all the ROS2 standard linters and static analysis tools for a C++ package as described in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#linters-and-static-analysis). Passing implies there are no linter/static errors when testing against CI of supported platforms.
Currently nightly test results can be seen here:
* [linux-aarch64_release](https://ci.ros2.org/view/nightly/job/nightly_linux-aarch64_release/lastBuild/testReport/rclcpp/)

View File

@@ -1,141 +0,0 @@
# Notes on statically typed parameters
## Introduction
Until ROS 2 Foxy, all parameters could change type anytime, except if the user installed a parameter callback to reject a change.
This could generate confusing errors, for example:
```
$ ros2 run demo_nodes_py listener &
$ ros2 param set /listener use_sim_time not_a_boolean
[ERROR] [1614712713.233733147] [listener]: use_sim_time parameter set to something besides a bool
Set parameter successful
$ ros2 param get /listener use_sim_time
String value is: not_a_boolean
```
For most use cases, having static parameter types is enough.
This article documents some of the decisions that were made when implementing static parameter types enforcement in:
* https://github.com/ros2/rclcpp/pull/1522
* https://github.com/ros2/rclpy/pull/683
## Allowing dynamically typed parameters
There might be some scenarios where dynamic typing is desired, so a `dynamic_typing` field was added to the [parameter descriptor](https://github.com/ros2/rcl_interfaces/blob/09b5ed93a733adb9deddc47f9a4a8c6e9f584667/rcl_interfaces/msg/ParameterDescriptor.msg#L25).
It defaults to `false`.
For example:
```cpp
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.dynamic_typing = true;
node->declare_parameter("dynamically_typed_parameter", rclcpp::ParameterValue{}, descriptor);
```
```py
rcl_interfaces.msg.ParameterDescriptor descriptor;
descriptor.dynamic_typing = True;
node.declare_parameter("dynamically_typed_parameter", None, descriptor);
```
## How is the parameter type specified?
The parameter type will be inferred from the default value provided when declaring it.
## Statically typed parameters when allowing undeclared parameters
When undeclared parameters are allowed and a parameter is set without a previous declaration, the parameter will be dynamically typed.
This is consistent with other allowed behaviors when undeclared parameters are allowed, e.g. trying to get an undeclared parameter returns "NOT_SET".
Parameter declarations will remain special and dynamic or static typing will be used based on the parameter descriptor (default to static).
## Declaring a parameter without a default value
There might be cases were a default value does not make sense and the user must always provide an override.
In those cases, the parameter type can be specified explicitly:
```cpp
// method signature
template<typename T>
Node::declare_parameter<T>(std::string name, rcl_interfaces::msg::ParameterDescriptor = rcl_interfaces::msg::ParameterDescriptor{});
// or alternatively
Node::declare_parameter(std::string name, rclcpp::ParameterType type, rcl_interfaces::msg::ParameterDescriptor = rcl_interfaces::msg::ParameterDescriptor{});
// examples
node->declare_parameter<int64_t>("my_integer_parameter"); // declare an integer parameter
node->declare_parameter("another_integer_parameter", rclcpp::ParameterType::PARAMETER_INTEGER); // another way to do the same
```
```py
# method signature
Node.declare_parameter(name: str, param_type: rclpy.Parameter.Type, descriptor: rcl_interfaces.msg.ParameterDescriptor = rcl_interfaces.msg.ParameterDescriptor())
# example
node.declare_parameter('my_integer_parameter', rclpy.Parameter.Type.INTEGER); # declare an integer parameter
```
If the parameter may be unused, but when used requires a parameter override, then you could conditionally declare it:
```cpp
auto mode = node->declare_parameter("mode", "modeA"); // "mode" parameter is an string
if (mode == "modeB") {
node->declare_parameter<int64_t>("param_needed_when_mode_b"); // when "modeB", the user must provide "param_needed_when_mode_b"
}
```
## Other migration notes
Declaring a parameter with only a name is deprecated:
```cpp
node->declare_parameter("my_param"); // this generates a build warning
```
```py
node.declare_parameter("my_param"); # this generates a python user warning
```
Before, you could initialize a parameter with the "NOT SET" value (in cpp `rclcpp::ParameterValue{}`, in python `None`).
Now this will throw an exception in both cases:
```cpp
node->declare_parameter("my_param", rclcpp::ParameterValue{}); // not valid, will throw exception
```
```py
node.declare_parameter("my_param", None); # not valid, will raise error
```
## Possible improvements
### Easier way to declare dynamically typed parameters
Declaring a dynamically typed parameter in `rclcpp` could be considered to be a bit verbose:
```cpp
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.dynamic_typing = true;
node->declare_parameter(name, rclcpp::ParameterValue{}, descriptor);
```
the following ways could be supported to make it simpler:
```cpp
node->declare_parameter(name, rclcpp::PARAMETER_DYNAMIC);
node->declare_parameter(name, default_value, rclcpp::PARAMETER_DYNAMIC);
```
or alternatively:
```cpp
node->declare_parameter(name, default_value, rclcpp::ParameterDescriptor{}.dynamic_typing());
```
For `rclpy`, there's already a short way to do it:
```py
node.declare_parameter(name, default_value, rclpy.ParameterDescriptor(dynamic_typing=true));
```

View File

@@ -50,6 +50,12 @@ struct AnyExecutable
std::shared_ptr<void> data;
};
namespace executor
{
using AnyExecutable [[deprecated("use rclcpp::AnyExecutable instead")]] = AnyExecutable;
} // namespace executor
} // namespace rclcpp
#endif // RCLCPP__ANY_EXECUTABLE_HPP_

View File

@@ -107,12 +107,12 @@ public:
TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
tracetools::get_symbol(shared_ptr_callback_));
get_symbol(shared_ptr_callback_));
} else if (shared_ptr_with_request_header_callback_) {
TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
tracetools::get_symbol(shared_ptr_with_request_header_callback_));
get_symbol(shared_ptr_with_request_header_callback_));
}
#endif // TRACETOOLS_DISABLED
}

View File

@@ -15,394 +15,253 @@
#ifndef RCLCPP__ANY_SUBSCRIPTION_CALLBACK_HPP_
#define RCLCPP__ANY_SUBSCRIPTION_CALLBACK_HPP_
#include <rmw/types.h>
#include <functional>
#include <memory>
#include <stdexcept>
#include <type_traits>
#include <utility>
#include <variant> // NOLINT[build/include_order]
#include "tracetools/tracetools.h"
#include "tracetools/utils.hpp"
#include "rclcpp/allocator/allocator_common.hpp"
#include "rclcpp/detail/subscription_callback_type_helper.hpp"
#include "rclcpp/function_traits.hpp"
#include "rclcpp/message_info.hpp"
template<class>
inline constexpr bool always_false_v = false;
#include "rclcpp/visibility_control.hpp"
#include "tracetools/tracetools.h"
#include "tracetools/utils.hpp"
namespace rclcpp
{
namespace detail
{
template<typename MessageT, typename AllocatorT>
struct MessageDeleterHelper
{
using MessageAllocTraits = allocator::AllocRebind<MessageT, AllocatorT>;
using MessageAlloc = typename MessageAllocTraits::allocator_type;
using MessageDeleter = allocator::Deleter<MessageAlloc, MessageT>;
};
template<typename MessageT, typename AllocatorT>
struct AnySubscriptionCallbackHelper
{
using MessageDeleter = typename MessageDeleterHelper<MessageT, AllocatorT>::MessageDeleter;
using ConstRefCallback =
std::function<void (const MessageT &)>;
using ConstRefWithInfoCallback =
std::function<void (const MessageT &, const rclcpp::MessageInfo &)>;
using UniquePtrCallback =
std::function<void (std::unique_ptr<MessageT, MessageDeleter>)>;
using UniquePtrWithInfoCallback =
std::function<void (std::unique_ptr<MessageT, MessageDeleter>, const rclcpp::MessageInfo &)>;
using SharedConstPtrCallback =
std::function<void (std::shared_ptr<const MessageT>)>;
using SharedConstPtrWithInfoCallback =
std::function<void (std::shared_ptr<const MessageT>, const rclcpp::MessageInfo &)>;
using ConstRefSharedConstPtrCallback =
std::function<void (const std::shared_ptr<const MessageT> &)>;
using ConstRefSharedConstPtrWithInfoCallback =
std::function<void (const std::shared_ptr<const MessageT> &, const rclcpp::MessageInfo &)>;
// Deprecated signatures:
using SharedPtrCallback =
std::function<void (std::shared_ptr<MessageT>)>;
using SharedPtrWithInfoCallback =
std::function<void (std::shared_ptr<MessageT>, const rclcpp::MessageInfo &)>;
using variant_type = std::variant<
ConstRefCallback,
ConstRefWithInfoCallback,
UniquePtrCallback,
UniquePtrWithInfoCallback,
SharedConstPtrCallback,
SharedConstPtrWithInfoCallback,
ConstRefSharedConstPtrCallback,
ConstRefSharedConstPtrWithInfoCallback,
SharedPtrCallback,
SharedPtrWithInfoCallback
>;
};
} // namespace detail
template<
typename MessageT,
typename AllocatorT = std::allocator<void>
>
template<typename MessageT, typename Alloc>
class AnySubscriptionCallback
{
private:
using HelperT = typename rclcpp::detail::AnySubscriptionCallbackHelper<MessageT, AllocatorT>;
using MessageDeleterHelper = rclcpp::detail::MessageDeleterHelper<MessageT, AllocatorT>;
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 MessageAllocTraits = typename MessageDeleterHelper::MessageAllocTraits;
using MessageAlloc = typename MessageDeleterHelper::MessageAlloc;
using MessageDeleter = typename MessageDeleterHelper::MessageDeleter;
using SharedPtrCallback = std::function<void (const std::shared_ptr<MessageT>)>;
using SharedPtrWithInfoCallback =
std::function<void (const std::shared_ptr<MessageT>, const rclcpp::MessageInfo &)>;
using ConstSharedPtrCallback = std::function<void (const std::shared_ptr<const MessageT>)>;
using ConstSharedPtrWithInfoCallback =
std::function<void (const std::shared_ptr<const MessageT>, const rclcpp::MessageInfo &)>;
using UniquePtrCallback = std::function<void (MessageUniquePtr)>;
using UniquePtrWithInfoCallback =
std::function<void (MessageUniquePtr, const rclcpp::MessageInfo &)>;
// See AnySubscriptionCallbackHelper for the types of these.
using ConstRefCallback = typename HelperT::ConstRefCallback;
using ConstRefWithInfoCallback = typename HelperT::ConstRefWithInfoCallback;
using UniquePtrCallback = typename HelperT::UniquePtrCallback;
using UniquePtrWithInfoCallback = typename HelperT::UniquePtrWithInfoCallback;
using SharedConstPtrCallback = typename HelperT::SharedConstPtrCallback;
using SharedConstPtrWithInfoCallback = typename HelperT::SharedConstPtrWithInfoCallback;
using ConstRefSharedConstPtrCallback =
typename HelperT::ConstRefSharedConstPtrCallback;
using ConstRefSharedConstPtrWithInfoCallback =
typename HelperT::ConstRefSharedConstPtrWithInfoCallback;
using SharedPtrCallback = typename HelperT::SharedPtrCallback;
using SharedPtrWithInfoCallback = typename HelperT::SharedPtrWithInfoCallback;
SharedPtrCallback shared_ptr_callback_;
SharedPtrWithInfoCallback shared_ptr_with_info_callback_;
ConstSharedPtrCallback const_shared_ptr_callback_;
ConstSharedPtrWithInfoCallback const_shared_ptr_with_info_callback_;
UniquePtrCallback unique_ptr_callback_;
UniquePtrWithInfoCallback unique_ptr_with_info_callback_;
public:
explicit
AnySubscriptionCallback(const AllocatorT & allocator = AllocatorT()) // NOLINT[runtime/explicit]
explicit AnySubscriptionCallback(std::shared_ptr<Alloc> allocator)
: shared_ptr_callback_(nullptr), shared_ptr_with_info_callback_(nullptr),
const_shared_ptr_callback_(nullptr), const_shared_ptr_with_info_callback_(nullptr),
unique_ptr_callback_(nullptr), unique_ptr_with_info_callback_(nullptr)
{
message_allocator_ = allocator;
allocator::set_allocator_for_deleter(&message_deleter_, &message_allocator_);
}
[[deprecated("use AnySubscriptionCallback(const AllocatorT & allocator) instead")]]
explicit
AnySubscriptionCallback(std::shared_ptr<AllocatorT> allocator) // NOLINT[runtime/explicit]
{
if (allocator == nullptr) {
throw std::runtime_error("invalid allocator");
}
message_allocator_ = *allocator;
allocator::set_allocator_for_deleter(&message_deleter_, &message_allocator_);
message_allocator_ = std::make_shared<MessageAlloc>(*allocator.get());
allocator::set_allocator_for_deleter(&message_deleter_, message_allocator_.get());
}
AnySubscriptionCallback(const AnySubscriptionCallback &) = default;
/// Generic function for setting the callback.
/**
* There are specializations that overload this in order to deprecate some
* callback signatures, and also to fix ambiguity between shared_ptr and
* unique_ptr callback signatures when using them with lambda functions.
*/
template<typename CallbackT>
AnySubscriptionCallback<MessageT, AllocatorT>
set(CallbackT callback)
{
// Use the SubscriptionCallbackTypeHelper to determine the actual type of
// the CallbackT, in terms of std::function<...>, which does not happen
// automatically with lambda functions in cases where the arguments can be
// converted to one another, e.g. shared_ptr and unique_ptr.
using scbth = detail::SubscriptionCallbackTypeHelper<MessageT, CallbackT>;
// Determine if the given CallbackT is a deprecated signature or not.
constexpr auto is_deprecated =
template<
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
typename scbth::callback_type,
std::function<void(std::shared_ptr<MessageT>)>
CallbackT,
SharedPtrCallback
>::value
||
>::type * = nullptr
>
void set(CallbackT callback)
{
shared_ptr_callback_ = callback;
}
template<
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
typename scbth::callback_type,
std::function<void(std::shared_ptr<MessageT>, const rclcpp::MessageInfo &)>
>::value;
// Use the discovered type to force the type of callback when assigning
// into the variant.
if constexpr (is_deprecated) {
// If deprecated, call sub-routine that is deprecated.
set_deprecated(static_cast<typename scbth::callback_type>(callback));
} else {
// Otherwise just assign it.
callback_variant_ = static_cast<typename scbth::callback_type>(callback);
}
// Return copy of self for easier testing, normally will be compiled out.
return *this;
}
/// Function for shared_ptr to non-const MessageT, which is deprecated.
// TODO(wjwwood): enable this deprecation after Galactic
// [[deprecated(
// "use 'void (std::shared_ptr<const MessageT>)' instead"
// )]]
void
set_deprecated(std::function<void(std::shared_ptr<MessageT>)> callback)
// set(CallbackT callback)
CallbackT,
SharedPtrWithInfoCallback
>::value
>::type * = nullptr
>
void set(CallbackT callback)
{
callback_variant_ = callback;
shared_ptr_with_info_callback_ = callback;
}
/// Function for shared_ptr to non-const MessageT with MessageInfo, which is deprecated.
// TODO(wjwwood): enable this deprecation after Galactic
// [[deprecated(
// "use 'void (std::shared_ptr<const MessageT>, const rclcpp::MessageInfo &)' instead"
// )]]
void
set_deprecated(
std::function<void(std::shared_ptr<MessageT>, const rclcpp::MessageInfo &)> callback)
template<
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
CallbackT,
ConstSharedPtrCallback
>::value
>::type * = nullptr
>
void set(CallbackT callback)
{
callback_variant_ = callback;
const_shared_ptr_callback_ = callback;
}
std::unique_ptr<MessageT, MessageDeleter>
create_unique_ptr_from_shared_ptr_message(const std::shared_ptr<const MessageT> & message)
template<
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
CallbackT,
ConstSharedPtrWithInfoCallback
>::value
>::type * = nullptr
>
void set(CallbackT callback)
{
auto ptr = MessageAllocTraits::allocate(message_allocator_, 1);
MessageAllocTraits::construct(message_allocator_, ptr, *message);
return std::unique_ptr<MessageT, MessageDeleter>(ptr, message_deleter_);
const_shared_ptr_with_info_callback_ = callback;
}
void
dispatch(
std::shared_ptr<MessageT> message,
const rclcpp::MessageInfo & message_info)
template<
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
CallbackT,
UniquePtrCallback
>::value
>::type * = nullptr
>
void set(CallbackT callback)
{
unique_ptr_callback_ = callback;
}
template<
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
CallbackT,
UniquePtrWithInfoCallback
>::value
>::type * = nullptr
>
void set(CallbackT callback)
{
unique_ptr_with_info_callback_ = callback;
}
void dispatch(
std::shared_ptr<MessageT> message, const rclcpp::MessageInfo & message_info)
{
TRACEPOINT(callback_start, static_cast<const void *>(this), false);
// Check if the variant is "unset", throw if it is.
if (callback_variant_.index() == 0) {
if (std::get<0>(callback_variant_) == nullptr) {
// This can happen if it is default initialized, or if it is assigned nullptr.
throw std::runtime_error("dispatch called on an unset AnySubscriptionCallback");
}
if (shared_ptr_callback_) {
shared_ptr_callback_(message);
} else if (shared_ptr_with_info_callback_) {
shared_ptr_with_info_callback_(message, message_info);
} else 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_) {
auto ptr = MessageAllocTraits::allocate(*message_allocator_.get(), 1);
MessageAllocTraits::construct(*message_allocator_.get(), ptr, *message);
unique_ptr_callback_(MessageUniquePtr(ptr, message_deleter_));
} else if (unique_ptr_with_info_callback_) {
auto ptr = MessageAllocTraits::allocate(*message_allocator_.get(), 1);
MessageAllocTraits::construct(*message_allocator_.get(), ptr, *message);
unique_ptr_with_info_callback_(MessageUniquePtr(ptr, message_deleter_), message_info);
} else {
throw std::runtime_error("unexpected message without any callback set");
}
// Dispatch.
std::visit(
[&message, &message_info, this](auto && callback) {
using T = std::decay_t<decltype(callback)>;
if constexpr (std::is_same_v<T, ConstRefCallback>) {
callback(*message);
} else if constexpr (std::is_same_v<T, ConstRefWithInfoCallback>) {
callback(*message, message_info);
} else if constexpr (std::is_same_v<T, UniquePtrCallback>) {
callback(create_unique_ptr_from_shared_ptr_message(message));
} else if constexpr (std::is_same_v<T, UniquePtrWithInfoCallback>) {
callback(create_unique_ptr_from_shared_ptr_message(message), message_info);
} else if constexpr ( // NOLINT[readability/braces]
std::is_same_v<T, SharedConstPtrCallback>||
std::is_same_v<T, ConstRefSharedConstPtrCallback>||
std::is_same_v<T, SharedPtrCallback>)
{
callback(message);
} else if constexpr ( // NOLINT[readability/braces]
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>||
std::is_same_v<T, SharedPtrWithInfoCallback>)
{
callback(message, message_info);
} else {
static_assert(always_false_v<T>, "unhandled callback type");
}
}, callback_variant_);
TRACEPOINT(callback_end, static_cast<const void *>(this));
}
void
dispatch_intra_process(
std::shared_ptr<const MessageT> message,
const rclcpp::MessageInfo & message_info)
void dispatch_intra_process(
ConstMessageSharedPtr message, const rclcpp::MessageInfo & message_info)
{
TRACEPOINT(callback_start, static_cast<const void *>(this), true);
// Check if the variant is "unset", throw if it is.
if (callback_variant_.index() == 0) {
if (std::get<0>(callback_variant_) == nullptr) {
// This can happen if it is default initialized, or if it is assigned nullptr.
throw std::runtime_error("dispatch called on an unset AnySubscriptionCallback");
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");
}
}
// Dispatch.
std::visit(
[&message, &message_info, this](auto && callback) {
using T = std::decay_t<decltype(callback)>;
if constexpr (std::is_same_v<T, ConstRefCallback>) {
callback(*message);
} else if constexpr (std::is_same_v<T, ConstRefWithInfoCallback>) {
callback(*message, message_info);
} else if constexpr ( // NOLINT[readability/braces]
std::is_same_v<T, UniquePtrCallback>||
std::is_same_v<T, SharedPtrCallback>)
{
callback(create_unique_ptr_from_shared_ptr_message(message));
} else if constexpr ( // NOLINT[readability/braces]
std::is_same_v<T, UniquePtrWithInfoCallback>||
std::is_same_v<T, SharedPtrWithInfoCallback>)
{
callback(create_unique_ptr_from_shared_ptr_message(message), message_info);
} else if constexpr ( // NOLINT[readability/braces]
std::is_same_v<T, SharedConstPtrCallback>||
std::is_same_v<T, ConstRefSharedConstPtrCallback>)
{
callback(message);
} else if constexpr ( // NOLINT[readability/braces]
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>)
{
callback(message, message_info);
} else {
static_assert(always_false_v<T>, "unhandled callback type");
}
}, callback_variant_);
TRACEPOINT(callback_end, static_cast<const void *>(this));
}
void
dispatch_intra_process(
std::unique_ptr<MessageT, MessageDeleter> message,
const rclcpp::MessageInfo & message_info)
void dispatch_intra_process(
MessageUniquePtr message, const rclcpp::MessageInfo & message_info)
{
TRACEPOINT(callback_start, static_cast<const void *>(this), true);
// Check if the variant is "unset", throw if it is.
if (callback_variant_.index() == 0) {
if (std::get<0>(callback_variant_) == nullptr) {
// This can happen if it is default initialized, or if it is assigned nullptr.
throw std::runtime_error("dispatch called on an unset AnySubscriptionCallback");
}
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 (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");
}
// Dispatch.
std::visit(
[&message, &message_info](auto && callback) {
using T = std::decay_t<decltype(callback)>;
if constexpr (std::is_same_v<T, ConstRefCallback>) {
callback(*message);
} else if constexpr (std::is_same_v<T, ConstRefWithInfoCallback>) {
callback(*message, message_info);
} else if constexpr ( // NOLINT[readability/braces]
std::is_same_v<T, UniquePtrCallback>||
std::is_same_v<T, SharedConstPtrCallback>||
std::is_same_v<T, ConstRefSharedConstPtrCallback>||
std::is_same_v<T, SharedPtrCallback>)
{
callback(std::move(message));
} else if constexpr ( // NOLINT[readability/braces]
std::is_same_v<T, UniquePtrWithInfoCallback>||
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>||
std::is_same_v<T, SharedPtrWithInfoCallback>)
{
callback(std::move(message), message_info);
} else {
static_assert(always_false_v<T>, "unhandled callback type");
}
}, callback_variant_);
TRACEPOINT(callback_end, static_cast<const void *>(this));
}
constexpr
bool
use_take_shared_method() const
bool use_take_shared_method() const
{
return
std::holds_alternative<SharedConstPtrCallback>(callback_variant_) ||
std::holds_alternative<SharedConstPtrWithInfoCallback>(callback_variant_) ||
std::holds_alternative<ConstRefSharedConstPtrCallback>(callback_variant_) ||
std::holds_alternative<ConstRefSharedConstPtrWithInfoCallback>(callback_variant_);
return const_shared_ptr_callback_ || const_shared_ptr_with_info_callback_;
}
void
register_callback_for_tracing()
void register_callback_for_tracing()
{
#ifndef TRACETOOLS_DISABLED
std::visit(
[this](auto && callback) {
TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
tracetools::get_symbol(callback));
}, callback_variant_);
if (shared_ptr_callback_) {
TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
get_symbol(shared_ptr_callback_));
} else if (shared_ptr_with_info_callback_) {
TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
get_symbol(shared_ptr_with_info_callback_));
} else if (unique_ptr_callback_) {
TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
get_symbol(unique_ptr_callback_));
} else if (unique_ptr_with_info_callback_) {
TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
get_symbol(unique_ptr_with_info_callback_));
}
#endif // TRACETOOLS_DISABLED
}
typename HelperT::variant_type &
get_variant()
{
return callback_variant_;
}
const typename HelperT::variant_type &
get_variant() const
{
return callback_variant_;
}
private:
// TODO(wjwwood): switch to inheriting from std::variant (i.e. HelperT::variant_type) once
// inheriting from std::variant is realistic (maybe C++23?), see:
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2162r0.html
// For now, compose the variant into this class as a private attribute.
typename HelperT::variant_type callback_variant_;
MessageAlloc message_allocator_;
std::shared_ptr<MessageAlloc> message_allocator_;
MessageDeleter message_deleter_;
};

View File

@@ -85,8 +85,8 @@ public:
* group, or after, is irrelevant; the callback group will be automatically
* added to the executor in either case.
*
* \param[in] group_type The type of the callback group.
* \param[in] automatically_add_to_executor_with_node A boolean that
* \param[in] group_type They type of the callback group.
* \param[in] automatically_add_to_executor_with_node a boolean which
* determines whether a callback group is automatically added to an executor
* with the node with which it is associated.
*/
@@ -222,6 +222,13 @@ private:
}
};
namespace callback_group
{
using CallbackGroupType [[deprecated("use rclcpp::CallbackGroupType instead")]] = CallbackGroupType;
using CallbackGroup [[deprecated("use rclcpp::CallbackGroup instead")]] = CallbackGroup;
} // namespace callback_group
} // namespace rclcpp
#endif // RCLCPP__CALLBACK_GROUP_HPP_

View File

@@ -136,7 +136,7 @@ private:
RCLCPP_PUBLIC
static void
on_time_jump(
const rcl_time_jump_t * time_jump,
const struct rcl_time_jump_t * time_jump,
bool before_jump,
void * user_data);

View File

@@ -23,7 +23,6 @@
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
@@ -48,17 +47,6 @@ public:
/// Forward declare WeakContextsWrapper
class WeakContextsWrapper;
class OnShutdownCallbackHandle
{
friend class Context;
public:
using OnShutdownCallbackType = std::function<void ()>;
private:
std::weak_ptr<OnShutdownCallbackType> callback;
};
/// Context which encapsulates shared state between nodes and other similar entities.
/**
* A context also represents the lifecycle between init and shutdown of rclcpp.
@@ -162,7 +150,7 @@ public:
*/
RCLCPP_PUBLIC
std::string
shutdown_reason() const;
shutdown_reason();
/// Shutdown the context, making it uninitialized and therefore invalid for derived entities.
/**
@@ -189,7 +177,7 @@ public:
bool
shutdown(const std::string & reason);
using OnShutdownCallback = OnShutdownCallbackHandle::OnShutdownCallbackType;
using OnShutdownCallback = std::function<void ()>;
/// Add a on_shutdown callback to be called when shutdown is called for this context.
/**
@@ -215,47 +203,23 @@ public:
OnShutdownCallback
on_shutdown(OnShutdownCallback callback);
/// Add a on_shutdown callback to be called when shutdown is called for this context.
/// Return the shutdown callbacks as const.
/**
* These callbacks will be called in the order they are added as the second
* to last step in shutdown().
*
* When shutdown occurs due to the signal handler, these callbacks are run
* asynchronously in the dedicated singal handling thread.
*
* Also, shutdown() may be called from the destructor of this function.
* Therefore, it is not safe to throw exceptions from these callbacks.
* Instead, log errors or use some other mechanism to indicate an error has
* occurred.
*
* On shutdown callbacks may be registered before init and after shutdown,
* and persist on repeated init's.
*
* \param[in] callback the on_shutdown callback to be registered
* \return the created callback handle
* Using the returned reference is not thread-safe with calls that modify
* the list of "on shutdown" callbacks, i.e. on_shutdown().
*/
RCLCPP_PUBLIC
virtual
OnShutdownCallbackHandle
add_on_shutdown_callback(OnShutdownCallback callback);
/// Remove an registered on_shutdown callbacks.
/**
* \param[in] callback_handle the on_shutdown callback handle to be removed.
* \return true if the callback is found and removed, otherwise false.
*/
RCLCPP_PUBLIC
virtual
bool
remove_on_shutdown_callback(const OnShutdownCallbackHandle & callback_handle);
const std::vector<OnShutdownCallback> &
get_on_shutdown_callbacks() const;
/// Return the shutdown callbacks.
/**
* Returned callbacks are a copy of the registered callbacks.
* Using the returned reference is not thread-safe with calls that modify
* the list of "on shutdown" callbacks, i.e. on_shutdown().
*/
RCLCPP_PUBLIC
std::vector<OnShutdownCallback>
get_on_shutdown_callbacks() const;
std::vector<OnShutdownCallback> &
get_on_shutdown_callbacks();
/// Return the internal rcl context.
RCLCPP_PUBLIC
@@ -322,7 +286,7 @@ private:
// This mutex is recursive so that the destructor can ensure atomicity
// between is_initialized and shutdown.
mutable std::recursive_mutex init_mutex_;
std::recursive_mutex init_mutex_;
std::shared_ptr<rcl_context_t> rcl_context_;
rclcpp::InitOptions init_options_;
std::string shutdown_reason_;
@@ -335,8 +299,8 @@ private:
// attempt to acquire another sub context.
std::recursive_mutex sub_contexts_mutex_;
std::unordered_set<std::shared_ptr<OnShutdownCallback>> on_shutdown_callbacks_;
mutable std::mutex on_shutdown_callbacks_mutex_;
std::vector<OnShutdownCallback> on_shutdown_callbacks_;
std::mutex on_shutdown_callbacks_mutex_;
/// Condition variable for timed sleep (see sleep_for).
std::condition_variable interrupt_condition_variable_;

View File

@@ -36,6 +36,22 @@ RCLCPP_PUBLIC
DefaultContext::SharedPtr
get_global_default_context();
namespace default_context
{
using DefaultContext
[[deprecated("use rclcpp::contexts::DefaultContext instead")]] = DefaultContext;
[[deprecated("use rclcpp::contexts::get_global_default_context() instead")]]
RCLCPP_PUBLIC
inline
DefaultContext::SharedPtr
get_global_default_context()
{
return rclcpp::contexts::get_global_default_context();
}
} // namespace default_context
} // namespace contexts
} // namespace rclcpp

View File

@@ -1,69 +0,0 @@
// Copyright 2020, Apex.AI 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_GENERIC_PUBLISHER_HPP_
#define RCLCPP__CREATE_GENERIC_PUBLISHER_HPP_
#include <memory>
#include <string>
#include <utility>
#include "rclcpp/generic_publisher.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/publisher_options.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/typesupport_helpers.hpp"
namespace rclcpp
{
/// Create and return a GenericPublisher.
/**
* The returned pointer will never be empty, but this function can throw various exceptions, for
* instance when the message's package can not be found on the AMENT_PREFIX_PATH.
*
* \param topics_interface NodeTopicsInterface pointer used in parts of the setup
* \param topic_name Topic name
* \param topic_type Topic type
* \param qos %QoS settings
* \param options %Publisher options.
* Not all publisher options are currently respected, the only relevant options for this
* publisher are `event_callbacks`, `use_default_callbacks`, and `%callback_group`.
*/
template<typename AllocatorT = std::allocator<void>>
std::shared_ptr<GenericPublisher> create_generic_publisher(
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr topics_interface,
const std::string & topic_name,
const std::string & topic_type,
const rclcpp::QoS & qos,
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options = (
rclcpp::PublisherOptionsWithAllocator<AllocatorT>()
)
)
{
auto ts_lib = rclcpp::get_typesupport_library(topic_type, "rosidl_typesupport_cpp");
auto pub = std::make_shared<GenericPublisher>(
topics_interface->get_node_base_interface(),
std::move(ts_lib),
topic_name,
topic_type,
qos,
options);
topics_interface->add_publisher(pub, options.callback_group);
return pub;
}
} // namespace rclcpp
#endif // RCLCPP__CREATE_GENERIC_PUBLISHER_HPP_

View File

@@ -1,79 +0,0 @@
// Copyright 2020, Apex.AI 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_GENERIC_SUBSCRIPTION_HPP_
#define RCLCPP__CREATE_GENERIC_SUBSCRIPTION_HPP_
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include "rcl/subscription.h"
#include "rclcpp/generic_subscription.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/serialized_message.hpp"
#include "rclcpp/subscription_options.hpp"
#include "rclcpp/typesupport_helpers.hpp"
namespace rclcpp
{
/// Create and return a GenericSubscription.
/**
* The returned pointer will never be empty, but this function can throw various exceptions, for
* instance when the message's package can not be found on the AMENT_PREFIX_PATH.
*
* \param topics_interface NodeTopicsInterface pointer used in parts of the setup.
* \param topic_name Topic name
* \param topic_type Topic type
* \param qos %QoS settings
* \param callback Callback for new messages of serialized form
* \param options %Publisher options.
* Not all publisher options are currently respected, the only relevant options for this
* publisher are `event_callbacks`, `use_default_callbacks`, and `%callback_group`.
*/
template<typename AllocatorT = std::allocator<void>>
std::shared_ptr<GenericSubscription> create_generic_subscription(
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr topics_interface,
const std::string & topic_name,
const std::string & topic_type,
const rclcpp::QoS & qos,
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
)
)
{
auto ts_lib = rclcpp::get_typesupport_library(
topic_type, "rosidl_typesupport_cpp");
auto subscription = std::make_shared<GenericSubscription>(
topics_interface->get_node_base_interface(),
std::move(ts_lib),
topic_name,
topic_type,
qos,
callback,
options);
topics_interface->add_subscription(subscription, options.callback_group);
return subscription;
}
} // namespace rclcpp
#endif // RCLCPP__CREATE_GENERIC_SUBSCRIPTION_HPP_

View File

@@ -80,10 +80,6 @@ create_publisher(
/**
* The NodeT type only needs to have a method called get_node_topics_interface()
* which returns a shared_ptr to a NodeTopicsInterface.
*
* In case `options.qos_overriding_options` is enabling qos parameter overrides,
* NodeT must also have a method called get_node_parameters_interface()
* which returns a shared_ptr to a NodeParametersInterface.
*/
template<
typename MessageT,

View File

@@ -101,7 +101,7 @@ create_subscription(
auto sub_call_back = [weak_subscription_topic_stats]() {
auto subscription_topic_stats = weak_subscription_topic_stats.lock();
if (subscription_topic_stats) {
subscription_topic_stats->publish_message_and_reset_measurements();
subscription_topic_stats->publish_message();
}
};
@@ -146,10 +146,6 @@ create_subscription(
* which returns a shared_ptr to a NodeTopicsInterface, or be a
* NodeTopicsInterface pointer itself.
*
* In case `options.qos_overriding_options` is enabling qos parameter overrides,
* NodeT must also have a method called get_node_parameters_interface()
* which returns a shared_ptr to a NodeParametersInterface.
*
* \tparam MessageT
* \tparam CallbackT
* \tparam AllocatorT

View File

@@ -1,76 +0,0 @@
// Copyright 2021 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DETAIL__MUTEX_TWO_PRIORITIES_HPP_
#define RCLCPP__DETAIL__MUTEX_TWO_PRIORITIES_HPP_
#include <condition_variable>
#include <mutex>
namespace rclcpp
{
namespace detail
{
/// \internal A mutex that has two locking mechanism, one with higher priority than the other.
/**
* After the current mutex owner release the lock, a thread that used the high
* priority mechanism will have priority over threads that used the low priority mechanism.
*/
class MutexTwoPriorities
{
public:
class HighPriorityLockable
{
public:
explicit HighPriorityLockable(MutexTwoPriorities & parent);
void lock();
void unlock();
private:
MutexTwoPriorities & parent_;
};
class LowPriorityLockable
{
public:
explicit LowPriorityLockable(MutexTwoPriorities & parent);
void lock();
void unlock();
private:
MutexTwoPriorities & parent_;
};
HighPriorityLockable
get_high_priority_lockable();
LowPriorityLockable
get_low_priority_lockable();
private:
std::condition_variable hp_cv_;
std::condition_variable lp_cv_;
std::mutex cv_mutex_;
size_t hp_waiting_count_{0u};
bool data_taken_{false};
};
} // namespace detail
} // namespace rclcpp
#endif // RCLCPP__DETAIL__MUTEX_TWO_PRIORITIES_HPP_

View File

@@ -1,164 +0,0 @@
// Copyright 2021 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DETAIL__SUBSCRIPTION_CALLBACK_TYPE_HELPER_HPP_
#define RCLCPP__DETAIL__SUBSCRIPTION_CALLBACK_TYPE_HELPER_HPP_
#include <memory>
#include <type_traits>
#include "rclcpp/function_traits.hpp"
#include "rclcpp/message_info.hpp"
namespace rclcpp
{
namespace detail
{
/// Template metaprogramming helper used to resolve the callback argument into a std::function.
/**
* Sometimes the CallbackT is a std::function already, but it could also be a
* function pointer, lambda, bind, or some variant of those.
* In some cases, like a lambda where the arguments can be converted between one
* another, e.g. std::function<void (shared_ptr<...>)> and
* std::function<void (unique_ptr<...>)>, you need to make that not ambiguous
* by checking the arguments independently using function traits rather than
* rely on overloading the two std::function types.
*
* This issue, with the lambda's, can be demonstrated with this minimal program:
*
* #include <functional>
* #include <memory>
*
* void f(std::function<void (std::shared_ptr<int>)>) {}
* void f(std::function<void (std::unique_ptr<int>)>) {}
*
* int main() {
* // Fails to compile with an "ambiguous call" error.
* f([](std::shared_ptr<int>){});
*
* // Works.
* std::function<void (std::shared_ptr<int>)> cb = [](std::shared_ptr<int>){};
* f(cb);
* }
*
* If this program ever starts working in a future version of C++, this class
* may become redundant.
*
* This helper works by using SFINAE with rclcpp::function_traits::same_arguments<>
* to narrow down the exact std::function<> type for the given CallbackT.
*/
template<typename MessageT, typename CallbackT, typename Enable = void>
struct SubscriptionCallbackTypeHelper
{
using callback_type = typename rclcpp::function_traits::as_std_function<CallbackT>::type;
};
template<typename MessageT, typename CallbackT>
struct SubscriptionCallbackTypeHelper<
MessageT,
CallbackT,
typename std::enable_if_t<
rclcpp::function_traits::same_arguments<
CallbackT,
std::function<void(std::shared_ptr<const MessageT>)>
>::value
>
>
{
using callback_type = std::function<void (std::shared_ptr<const MessageT>)>;
};
template<typename MessageT, typename CallbackT>
struct SubscriptionCallbackTypeHelper<
MessageT,
CallbackT,
typename std::enable_if_t<
rclcpp::function_traits::same_arguments<
CallbackT,
std::function<void(std::shared_ptr<const MessageT>, const rclcpp::MessageInfo &)>
>::value
>
>
{
using callback_type =
std::function<void (std::shared_ptr<const MessageT>, const rclcpp::MessageInfo &)>;
};
template<typename MessageT, typename CallbackT>
struct SubscriptionCallbackTypeHelper<
MessageT,
CallbackT,
typename std::enable_if_t<
rclcpp::function_traits::same_arguments<
CallbackT,
std::function<void(const std::shared_ptr<const MessageT> &)>
>::value
>
>
{
using callback_type = std::function<void (const std::shared_ptr<const MessageT> &)>;
};
template<typename MessageT, typename CallbackT>
struct SubscriptionCallbackTypeHelper<
MessageT,
CallbackT,
typename std::enable_if_t<
rclcpp::function_traits::same_arguments<
CallbackT,
std::function<void(const std::shared_ptr<const MessageT> &, const rclcpp::MessageInfo &)>
>::value
>
>
{
using callback_type =
std::function<void (const std::shared_ptr<const MessageT> &, const rclcpp::MessageInfo &)>;
};
template<typename MessageT, typename CallbackT>
struct SubscriptionCallbackTypeHelper<
MessageT,
CallbackT,
typename std::enable_if_t<
rclcpp::function_traits::same_arguments<
CallbackT,
std::function<void(std::shared_ptr<MessageT>)>
>::value
>
>
{
using callback_type = std::function<void (std::shared_ptr<MessageT>)>;
};
template<typename MessageT, typename CallbackT>
struct SubscriptionCallbackTypeHelper<
MessageT,
CallbackT,
typename std::enable_if_t<
rclcpp::function_traits::same_arguments<
CallbackT,
std::function<void(std::shared_ptr<MessageT>, const rclcpp::MessageInfo &)>
>::value
>
>
{
using callback_type =
std::function<void (std::shared_ptr<MessageT>, const rclcpp::MessageInfo &)>;
};
} // namespace detail
} // namespace rclcpp
#endif // RCLCPP__DETAIL__SUBSCRIPTION_CALLBACK_TYPE_HELPER_HPP_

View File

@@ -137,9 +137,6 @@ public:
static Duration
from_nanoseconds(rcl_duration_value_t nanoseconds);
static Duration
from_rmw_time(rmw_time_t duration);
/// Convert Duration into a std::chrono::Duration.
template<class DurationT>
DurationT

View File

@@ -282,20 +282,6 @@ class ParameterModifiedInCallbackException : public std::runtime_error
using std::runtime_error::runtime_error;
};
/// Thrown when an uninitialized parameter is accessed.
class ParameterUninitializedException : public std::runtime_error
{
public:
/// Construct an instance.
/**
* \param[in] name the name of the parameter.
* \param[in] message custom exception message.
*/
explicit ParameterUninitializedException(const std::string & name)
: std::runtime_error("parameter '" + name + "' is not initialized")
{}
};
/// Thrown if the QoS overrides provided aren't valid.
class InvalidQosOverridesException : public std::runtime_error
{
@@ -303,13 +289,6 @@ class InvalidQosOverridesException : public std::runtime_error
using std::runtime_error::runtime_error;
};
/// Thrown if a QoS compatibility check fails.
class QoSCheckCompatibleException : public std::runtime_error
{
// Inherit constructors from runtime_error.
using std::runtime_error::runtime_error;
};
} // namespace exceptions
} // namespace rclcpp

View File

@@ -30,7 +30,6 @@
#include "rcl/guard_condition.h"
#include "rcl/wait.h"
#include "rclcpp/context.hpp"
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/executor_options.hpp"
@@ -449,7 +448,7 @@ protected:
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
get_node_by_group(
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
WeakCallbackGroupsToNodesMap weak_groups_to_nodes,
rclcpp::CallbackGroup::SharedPtr group);
/// Return true if the node has been added to this executor.
@@ -461,7 +460,7 @@ protected:
bool
has_node(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) const;
WeakCallbackGroupsToNodesMap weak_groups_to_nodes) const;
RCLCPP_PUBLIC
rclcpp::CallbackGroup::SharedPtr
@@ -477,7 +476,7 @@ protected:
rclcpp::CallbackGroup::SharedPtr group_ptr,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
bool notify = true) RCPPUTILS_TSA_REQUIRES(mutex_);
bool notify = true);
/// Remove a callback group from the executor.
/**
@@ -488,7 +487,7 @@ protected:
remove_callback_group_from_map(
rclcpp::CallbackGroup::SharedPtr group_ptr,
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
bool notify = true) RCPPUTILS_TSA_REQUIRES(mutex_);
bool notify = true);
RCLCPP_PUBLIC
bool
@@ -498,7 +497,7 @@ protected:
bool
get_next_ready_executable_from_map(
AnyExecutable & any_executable,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
WeakCallbackGroupsToNodesMap weak_groups_to_nodes);
RCLCPP_PUBLIC
bool
@@ -519,7 +518,7 @@ protected:
*/
RCLCPP_PUBLIC
virtual void
add_callback_groups_from_nodes_associated_to_executor() RCPPUTILS_TSA_REQUIRES(mutex_);
add_callback_groups_from_nodes_associated_to_executor();
/// Spinning state, used to prevent multi threaded calls to spin and to cancel blocking spins.
std::atomic_bool spinning;
@@ -533,11 +532,10 @@ protected:
rcl_wait_set_t wait_set_ = rcl_get_zero_initialized_wait_set();
// Mutex to protect the subsequent memory_strategy_.
mutable std::mutex mutex_;
std::mutex memory_strategy_mutex_;
/// The memory strategy: an interface for handling user-defined memory allocation strategies.
memory_strategy::MemoryStrategy::SharedPtr
memory_strategy_ RCPPUTILS_TSA_PT_GUARDED_BY(mutex_);
memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;
/// The context associated with this executor.
std::shared_ptr<rclcpp::Context> context_;
@@ -545,7 +543,7 @@ protected:
RCLCPP_DISABLE_COPY(Executor)
RCLCPP_PUBLIC
virtual void
void
spin_once_impl(std::chrono::nanoseconds timeout);
typedef std::map<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr,
@@ -554,29 +552,27 @@ protected:
WeakNodesToGuardConditionsMap;
/// maps nodes to guard conditions
WeakNodesToGuardConditionsMap
weak_nodes_to_guard_conditions_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
WeakNodesToGuardConditionsMap weak_nodes_to_guard_conditions_;
/// maps callback groups associated to nodes
WeakCallbackGroupsToNodesMap
weak_groups_associated_with_executor_to_nodes_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
WeakCallbackGroupsToNodesMap weak_groups_associated_with_executor_to_nodes_;
/// maps callback groups to nodes associated with executor
WeakCallbackGroupsToNodesMap
weak_groups_to_nodes_associated_with_executor_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
WeakCallbackGroupsToNodesMap weak_groups_to_nodes_associated_with_executor_;
/// maps all callback groups to nodes
WeakCallbackGroupsToNodesMap
weak_groups_to_nodes_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
WeakCallbackGroupsToNodesMap weak_groups_to_nodes_;
/// nodes that are associated with the executor
std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>
weak_nodes_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// shutdown callback handle registered to Context
rclcpp::OnShutdownCallbackHandle shutdown_callback_handle_;
std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> weak_nodes_;
};
namespace executor
{
using Executor [[deprecated("use rclcpp::Executor instead")]] = rclcpp::Executor;
} // namespace executor
} // namespace rclcpp
#endif // RCLCPP__EXECUTOR_HPP_

View File

@@ -38,6 +38,20 @@ struct ExecutorOptions
size_t max_conditions;
};
namespace executor
{
using ExecutorArgs [[deprecated("use rclcpp::ExecutorOptions instead")]] = ExecutorOptions;
[[deprecated("use rclcpp::ExecutorOptions() instead")]]
inline
rclcpp::ExecutorOptions
create_default_executor_arguments()
{
return rclcpp::ExecutorOptions();
}
} // namespace executor
} // namespace rclcpp
#endif // RCLCPP__EXECUTOR_OPTIONS_HPP_

View File

@@ -22,7 +22,6 @@
#include <thread>
#include <unordered_map>
#include "rclcpp/detail/mutex_two_priorities.hpp"
#include "rclcpp/executor.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/memory_strategies.hpp"
@@ -82,7 +81,7 @@ protected:
private:
RCLCPP_DISABLE_COPY(MultiThreadedExecutor)
detail::MutexTwoPriorities wait_mutex_;
std::mutex wait_mutex_;
size_t number_of_threads_;
bool yield_before_execute_;
std::chrono::nanoseconds next_exec_timeout_;

View File

@@ -68,10 +68,6 @@ public:
rcl_guard_condition_t * executor_guard_condition);
/// Finalize StaticExecutorEntitiesCollector to clear resources
RCLCPP_PUBLIC
bool
is_init() {return initialized_;}
RCLCPP_PUBLIC
void
fini();
@@ -343,9 +339,6 @@ private:
/// Executable list: timers, subscribers, clients, services and waitables
rclcpp::experimental::ExecutableList exec_list_;
/// Bool to check if the entities collector has been initialized
bool initialized_ = false;
};
} // namespace executors

View File

@@ -15,7 +15,6 @@
#ifndef RCLCPP__EXECUTORS__STATIC_SINGLE_THREADED_EXECUTOR_HPP_
#define RCLCPP__EXECUTORS__STATIC_SINGLE_THREADED_EXECUTOR_HPP_
#include <chrono>
#include <cassert>
#include <cstdlib>
#include <memory>
@@ -79,42 +78,6 @@ public:
void
spin() override;
/// Static executor implementation of spin some
/**
* This non-blocking function will execute entities that
* were ready when this API was called, until timeout or no
* more work available. Entities that got ready while
* executing work, won't be taken into account here.
*
* Example:
* while(condition) {
* spin_some();
* sleep(); // User should have some sync work or
* // sleep to avoid a 100% CPU usage
* }
*/
RCLCPP_PUBLIC
void
spin_some(std::chrono::nanoseconds max_duration = std::chrono::nanoseconds(0)) override;
/// Static executor implementation of spin all
/**
* This non-blocking function will execute entities until
* timeout or no more work available. If new entities get ready
* while executing work available, they will be executed
* as long as the timeout hasn't expired.
*
* Example:
* while(condition) {
* spin_all();
* sleep(); // User should have some sync work or
* // sleep to avoid a 100% CPU usage
* }
*/
RCLCPP_PUBLIC
void
spin_all(std::chrono::nanoseconds max_duration) override;
/// Add a callback group to an executor.
/**
* \sa rclcpp::Executor::add_callback_group
@@ -192,23 +155,113 @@ public:
std::vector<rclcpp::CallbackGroup::WeakPtr>
get_automatically_added_callback_groups_from_nodes() override;
protected:
/// Spin (blocking) until the future is complete, it times out waiting, or rclcpp is interrupted.
/**
* @brief Executes ready executables from wait set.
* @param spin_once if true executes only the first ready executable.
* @return true if any executable was ready.
* \param[in] future The future to wait on. If this function returns SUCCESS, the future can be
* accessed without blocking (though it may still throw an exception).
* \param[in] timeout Optional timeout parameter, which gets passed to
* Executor::execute_ready_executables.
* `-1` is block forever, `0` is non-blocking.
* If the time spent inside the blocking loop exceeds this timeout, return a TIMEOUT return
* code.
* \return The return code, one of `SUCCESS`, `INTERRUPTED`, or `TIMEOUT`.
*
* Example usage:
* rclcpp::executors::StaticSingleThreadedExecutor exec;
* // ... other part of code like creating node
* // define future
* exec.add_node(node);
* exec.spin_until_future_complete(future);
*/
template<typename FutureT, typename TimeRepT = int64_t, typename TimeT = std::milli>
rclcpp::FutureReturnCode
spin_until_future_complete(
FutureT & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
std::future_status status = future.wait_for(std::chrono::seconds(0));
if (status == std::future_status::ready) {
return rclcpp::FutureReturnCode::SUCCESS;
}
auto end_time = std::chrono::steady_clock::now();
std::chrono::nanoseconds timeout_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(
timeout);
if (timeout_ns > std::chrono::nanoseconds::zero()) {
end_time += timeout_ns;
}
std::chrono::nanoseconds timeout_left = timeout_ns;
entities_collector_->init(&wait_set_, memory_strategy_, &interrupt_guard_condition_);
RCLCPP_SCOPE_EXIT(entities_collector_->fini());
while (rclcpp::ok(this->context_)) {
// Do one set of work.
entities_collector_->refresh_wait_set(timeout_left);
execute_ready_executables();
// Check if the future is set, return SUCCESS if it is.
status = future.wait_for(std::chrono::seconds(0));
if (status == std::future_status::ready) {
return rclcpp::FutureReturnCode::SUCCESS;
}
// If the original timeout is < 0, then this is blocking, never TIMEOUT.
if (timeout_ns < std::chrono::nanoseconds::zero()) {
continue;
}
// Otherwise check if we still have time to wait, return TIMEOUT if not.
auto now = std::chrono::steady_clock::now();
if (now >= end_time) {
return rclcpp::FutureReturnCode::TIMEOUT;
}
// Subtract the elapsed time from the original timeout.
timeout_left = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - now);
}
// The future did not complete before ok() returned false, return INTERRUPTED.
return rclcpp::FutureReturnCode::INTERRUPTED;
}
/// Not yet implemented, see https://github.com/ros2/rclcpp/issues/1219 for tracking
RCLCPP_PUBLIC
void
spin_some(std::chrono::nanoseconds max_duration = std::chrono::nanoseconds(0)) override
{
(void)max_duration;
throw rclcpp::exceptions::UnimplementedError(
"spin_some is not implemented for StaticSingleThreadedExecutor, use spin or "
"spin_until_future_complete");
}
/// Not yet implemented, see https://github.com/ros2/rclcpp/issues/1219 for tracking
RCLCPP_PUBLIC
void
spin_all(std::chrono::nanoseconds) override
{
throw rclcpp::exceptions::UnimplementedError(
"spin_all is not implemented for StaticSingleThreadedExecutor, use spin or "
"spin_until_future_complete");
}
/// Not yet implemented, see https://github.com/ros2/rclcpp/issues/1219 for tracking
RCLCPP_PUBLIC
void
spin_once(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1)) override
{
(void)timeout;
throw rclcpp::exceptions::UnimplementedError(
"spin_once is not implemented for StaticSingleThreadedExecutor, use spin or "
"spin_until_future_complete");
}
protected:
/// Check which executables in ExecutableList struct are ready from wait_set and execute them.
/**
* \param[in] exec_list Structure that can hold subscriptionbases, timerbases, etc
* \param[in] timeout Optional timeout parameter.
*/
RCLCPP_PUBLIC
bool
execute_ready_executables(bool spin_once = false);
RCLCPP_PUBLIC
void
spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive);
RCLCPP_PUBLIC
void
spin_once_impl(std::chrono::nanoseconds timeout) override;
execute_ready_executables();
private:
RCLCPP_DISABLE_COPY(StaticSingleThreadedExecutor)

View File

@@ -202,8 +202,7 @@ public:
// None of the buffers require ownership, so we promote the pointer
std::shared_ptr<MessageT> msg = std::move(message);
this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter>(
msg, sub_ids.take_shared_subscriptions);
this->template add_shared_msg_to_buffers<MessageT>(msg, sub_ids.take_shared_subscriptions);
} else if (!sub_ids.take_ownership_subscriptions.empty() && // NOLINT
sub_ids.take_shared_subscriptions.size() <= 1)
{
@@ -228,7 +227,7 @@ public:
// for the buffers that do not require ownership
auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(*allocator, *message);
this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter>(
this->template add_shared_msg_to_buffers<MessageT>(
shared_msg, sub_ids.take_shared_subscriptions);
this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter>(
std::move(message), sub_ids.take_ownership_subscriptions, allocator);
@@ -264,7 +263,7 @@ public:
// If there are no owning, just convert to shared.
std::shared_ptr<MessageT> shared_msg = std::move(message);
if (!sub_ids.take_shared_subscriptions.empty()) {
this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter>(
this->template add_shared_msg_to_buffers<MessageT>(
shared_msg, sub_ids.take_shared_subscriptions);
}
return shared_msg;
@@ -274,7 +273,7 @@ public:
auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(*allocator, *message);
if (!sub_ids.take_shared_subscriptions.empty()) {
this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter>(
this->template add_shared_msg_to_buffers<MessageT>(
shared_msg,
sub_ids.take_shared_subscriptions);
}
@@ -308,7 +307,7 @@ private:
{
SubscriptionInfo() = default;
rclcpp::experimental::SubscriptionIntraProcessBase::WeakPtr subscription;
rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr subscription;
rmw_qos_profile_t qos;
const char * topic_name;
bool use_take_shared_method;
@@ -351,10 +350,7 @@ private:
bool
can_communicate(PublisherInfo pub_info, SubscriptionInfo sub_info) const;
template<
typename MessageT,
typename Alloc,
typename Deleter>
template<typename MessageT>
void
add_shared_msg_to_buffers(
std::shared_ptr<const MessageT> message,
@@ -365,23 +361,13 @@ private:
if (subscription_it == subscriptions_.end()) {
throw std::runtime_error("subscription has unexpectedly gone out of scope");
}
auto subscription_base = subscription_it->second.subscription.lock();
if (subscription_base) {
auto subscription = std::dynamic_pointer_cast<
rclcpp::experimental::SubscriptionIntraProcess<MessageT, Alloc, Deleter>
>(subscription_base);
if (nullptr == subscription) {
throw std::runtime_error(
"failed to dynamic cast SubscriptionIntraProcessBase to "
"SubscriptionIntraProcess<MessageT, Alloc, Deleter>, which "
"can happen when the publisher and subscription use different "
"allocator types, which is not supported");
}
auto subscription_base = subscription_it->second.subscription;
subscription->provide_intra_process_message(message);
} else {
subscriptions_.erase(id);
}
auto subscription = std::static_pointer_cast<
rclcpp::experimental::SubscriptionIntraProcess<MessageT>
>(subscription_base);
subscription->provide_intra_process_message(message);
}
}
@@ -403,34 +389,24 @@ private:
if (subscription_it == subscriptions_.end()) {
throw std::runtime_error("subscription has unexpectedly gone out of scope");
}
auto subscription_base = subscription_it->second.subscription.lock();
if (subscription_base) {
auto subscription = std::dynamic_pointer_cast<
rclcpp::experimental::SubscriptionIntraProcess<MessageT, Alloc, Deleter>
>(subscription_base);
if (nullptr == subscription) {
throw std::runtime_error(
"failed to dynamic cast SubscriptionIntraProcessBase to "
"SubscriptionIntraProcess<MessageT, Alloc, Deleter>, which "
"can happen when the publisher and subscription use different "
"allocator types, which is not supported");
}
auto subscription_base = subscription_it->second.subscription;
if (std::next(it) == subscription_ids.end()) {
// If this is the last subscription, give up ownership
subscription->provide_intra_process_message(std::move(message));
} else {
// Copy the message since we have additional subscriptions to serve
MessageUniquePtr copy_message;
Deleter deleter = message.get_deleter();
auto ptr = MessageAllocTraits::allocate(*allocator.get(), 1);
MessageAllocTraits::construct(*allocator.get(), ptr, *message);
copy_message = MessageUniquePtr(ptr, deleter);
auto subscription = std::static_pointer_cast<
rclcpp::experimental::SubscriptionIntraProcess<MessageT>
>(subscription_base);
subscription->provide_intra_process_message(std::move(copy_message));
}
if (std::next(it) == subscription_ids.end()) {
// If this is the last subscription, give up ownership
subscription->provide_intra_process_message(std::move(message));
} else {
subscriptions_.erase(subscription_it);
// Copy the message since we have additional subscriptions to serve
MessageUniquePtr copy_message;
Deleter deleter = message.get_deleter();
auto ptr = MessageAllocTraits::allocate(*allocator.get(), 1);
MessageAllocTraits::construct(*allocator.get(), ptr, *message);
copy_message = MessageUniquePtr(ptr, deleter);
subscription->provide_intra_process_message(std::move(copy_message));
}
}
}

View File

@@ -162,32 +162,6 @@ struct same_arguments : std::is_same<
>
{};
namespace detail
{
template<typename ReturnTypeT, typename ... Args>
struct as_std_function_helper;
template<typename ReturnTypeT, typename ... Args>
struct as_std_function_helper<ReturnTypeT, std::tuple<Args ...>>
{
using type = std::function<ReturnTypeT(Args ...)>;
};
} // namespace detail
template<
typename FunctorT,
typename FunctionTraits = function_traits<FunctorT>
>
struct as_std_function
{
using type = typename detail::as_std_function_helper<
typename FunctionTraits::return_type,
typename FunctionTraits::arguments
>::type;
};
} // namespace function_traits
} // namespace rclcpp

View File

@@ -1,127 +0,0 @@
// Copyright 2018, Bosch Software Innovations GmbH.
// Copyright 2021, Apex.AI 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__GENERIC_PUBLISHER_HPP_
#define RCLCPP__GENERIC_PUBLISHER_HPP_
#include <memory>
#include <string>
#include "rcpputils/shared_library.hpp"
#include "rclcpp/callback_group.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/publisher_base.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/serialized_message.hpp"
#include "rclcpp/typesupport_helpers.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
/// %Publisher for serialized messages whose type is not known at compile time.
/**
* Since the type is not known at compile time, this is not a template, and the dynamic library
* containing type support information has to be identified and loaded based on the type name.
*
* It does not support intra-process handling.
*/
class GenericPublisher : public rclcpp::PublisherBase
{
public:
// cppcheck-suppress unknownMacro
RCLCPP_SMART_PTR_DEFINITIONS(GenericPublisher)
/// Constructor.
/**
* In order to properly publish to a topic, this publisher needs to be added to
* the node_topic_interface of the node passed into this constructor.
*
* \sa rclcpp::Node::create_generic_publisher() or rclcpp::create_generic_publisher() for
* creating an instance of this class and adding it to the node_topic_interface.
*
* \param node_base Pointer to parent node's NodeBaseInterface
* \param ts_lib Type support library, needs to correspond to topic_type
* \param topic_name Topic name
* \param topic_type Topic type
* \param qos %QoS settings
* \param callback Callback for new messages of serialized form
* \param options %Publisher options.
* Not all publisher options are currently respected, the only relevant options for this
* publisher are `event_callbacks`, `use_default_callbacks`, and `%callback_group`.
*/
template<typename AllocatorT = std::allocator<void>>
GenericPublisher(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
std::shared_ptr<rcpputils::SharedLibrary> ts_lib,
const std::string & topic_name,
const std::string & topic_type,
const rclcpp::QoS & qos,
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
: rclcpp::PublisherBase(
node_base,
topic_name,
*rclcpp::get_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
options.template to_rcl_publisher_options<rclcpp::SerializedMessage>(qos)),
ts_lib_(ts_lib)
{
// This is unfortunately duplicated with the code in publisher.hpp.
// TODO(nnmm): Deduplicate by moving this into PublisherBase.
if (options.event_callbacks.deadline_callback) {
this->add_event_handler(
options.event_callbacks.deadline_callback,
RCL_PUBLISHER_OFFERED_DEADLINE_MISSED);
}
if (options.event_callbacks.liveliness_callback) {
this->add_event_handler(
options.event_callbacks.liveliness_callback,
RCL_PUBLISHER_LIVELINESS_LOST);
}
if (options.event_callbacks.incompatible_qos_callback) {
this->add_event_handler(
options.event_callbacks.incompatible_qos_callback,
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
} else if (options.use_default_callbacks) {
// Register default callback when not specified
try {
this->add_event_handler(
[this](QOSOfferedIncompatibleQoSInfo & info) {
this->default_incompatible_qos_callback(info);
},
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
} catch (UnsupportedEventTypeException & /*exc*/) {
// pass
}
}
}
RCLCPP_PUBLIC
virtual ~GenericPublisher() = default;
/// Publish a rclcpp::SerializedMessage.
RCLCPP_PUBLIC
void publish(const rclcpp::SerializedMessage & message);
private:
// The type support library should stay loaded, so it is stored in the GenericPublisher
std::shared_ptr<rcpputils::SharedLibrary> ts_lib_;
};
} // namespace rclcpp
#endif // RCLCPP__GENERIC_PUBLISHER_HPP_

View File

@@ -1,161 +0,0 @@
// Copyright 2018, Bosch Software Innovations GmbH.
// Copyright 2021, Apex.AI 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__GENERIC_SUBSCRIPTION_HPP_
#define RCLCPP__GENERIC_SUBSCRIPTION_HPP_
#include <functional>
#include <memory>
#include <string>
#include "rcpputils/shared_library.hpp"
#include "rclcpp/callback_group.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/serialized_message.hpp"
#include "rclcpp/subscription_base.hpp"
#include "rclcpp/typesupport_helpers.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
/// %Subscription for serialized messages whose type is not known at compile time.
/**
* Since the type is not known at compile time, this is not a template, and the dynamic library
* containing type support information has to be identified and loaded based on the type name.
*
* It does not support intra-process handling.
*/
class GenericSubscription : public rclcpp::SubscriptionBase
{
public:
// cppcheck-suppress unknownMacro
RCLCPP_SMART_PTR_DEFINITIONS(GenericSubscription)
/// Constructor.
/**
* In order to properly subscribe to a topic, this subscription needs to be added to
* the node_topic_interface of the node passed into this constructor.
*
* \sa rclcpp::Node::create_generic_subscription() or rclcpp::create_generic_subscription() for
* creating an instance of this class and adding it to the node_topic_interface.
*
* \param node_base Pointer to parent node's NodeBaseInterface
* \param ts_lib Type support library, needs to correspond to topic_type
* \param topic_name Topic name
* \param topic_type Topic type
* \param qos %QoS settings
* \param callback Callback for new messages of serialized form
* \param options %Subscription options.
* Not all subscription options are currently respected, the only relevant options for this
* subscription are `event_callbacks`, `use_default_callbacks`, `ignore_local_publications`, and
* `%callback_group`.
*/
template<typename AllocatorT = std::allocator<void>>
GenericSubscription(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const std::shared_ptr<rcpputils::SharedLibrary> ts_lib,
const std::string & topic_name,
const std::string & topic_type,
const rclcpp::QoS & qos,
// TODO(nnmm): Add variant for callback with message info. See issue #1604.
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options)
: SubscriptionBase(
node_base,
*rclcpp::get_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
topic_name,
options.template to_rcl_subscription_options<rclcpp::SerializedMessage>(qos),
true),
callback_(callback),
ts_lib_(ts_lib)
{
// This is unfortunately duplicated with the code in subscription.hpp.
// TODO(nnmm): Deduplicate by moving this into SubscriptionBase.
if (options.event_callbacks.deadline_callback) {
this->add_event_handler(
options.event_callbacks.deadline_callback,
RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED);
}
if (options.event_callbacks.liveliness_callback) {
this->add_event_handler(
options.event_callbacks.liveliness_callback,
RCL_SUBSCRIPTION_LIVELINESS_CHANGED);
}
if (options.event_callbacks.incompatible_qos_callback) {
this->add_event_handler(
options.event_callbacks.incompatible_qos_callback,
RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
} else if (options.use_default_callbacks) {
// Register default callback when not specified
try {
this->add_event_handler(
[this](QOSRequestedIncompatibleQoSInfo & info) {
this->default_incompatible_qos_callback(info);
},
RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
} catch (UnsupportedEventTypeException & /*exc*/) {
// pass
}
}
if (options.event_callbacks.message_lost_callback) {
this->add_event_handler(
options.event_callbacks.message_lost_callback,
RCL_SUBSCRIPTION_MESSAGE_LOST);
}
}
RCLCPP_PUBLIC
virtual ~GenericSubscription() = default;
// Same as create_serialized_message() as the subscription is to serialized_messages only
RCLCPP_PUBLIC
std::shared_ptr<void> create_message() override;
RCLCPP_PUBLIC
std::shared_ptr<rclcpp::SerializedMessage> create_serialized_message() override;
/// Cast the message to a rclcpp::SerializedMessage and call the callback.
RCLCPP_PUBLIC
void handle_message(
std::shared_ptr<void> & message, const rclcpp::MessageInfo & message_info) override;
/// This function is currently not implemented.
RCLCPP_PUBLIC
void handle_loaned_message(
void * loaned_message, const rclcpp::MessageInfo & message_info) override;
// Same as return_serialized_message() as the subscription is to serialized_messages only
RCLCPP_PUBLIC
void return_message(std::shared_ptr<void> & message) override;
RCLCPP_PUBLIC
void return_serialized_message(std::shared_ptr<rclcpp::SerializedMessage> & message) override;
private:
RCLCPP_DISABLE_COPY(GenericSubscription)
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback_;
// The type support library should stay loaded, so it is stored in the GenericSubscription
std::shared_ptr<rcpputils::SharedLibrary> ts_lib_;
};
} // namespace rclcpp
#endif // RCLCPP__GENERIC_SUBSCRIPTION_HPP_

View File

@@ -183,30 +183,14 @@ public:
/**
* A call to `release()` will unmanage the memory for the ROS message.
* That means that the destructor of this class will not free the memory on scope exit.
* If the message is loaned from the middleware but not be published, the user needs to call
* `rcl_return_loaned_message_from_publisher` manually.
* If the memory is from the local allocator, the memory is freed when the unique pointer
* goes out instead.
*
* \return std::unique_ptr to the message instance.
* \return Raw pointer to the message instance.
*/
std::unique_ptr<MessageT, std::function<void(MessageT *)>>
release()
MessageT * release()
{
auto msg = message_;
message_ = nullptr;
if (pub_.can_loan_messages()) {
return std::unique_ptr<MessageT, std::function<void(MessageT *)>>(msg, [](MessageT *) {});
}
return std::unique_ptr<MessageT, std::function<void(MessageT *)>>(
msg,
[allocator = message_allocator_](MessageT * msg_ptr) mutable {
// call destructor before deallocating
msg_ptr->~MessageT();
allocator.deallocate(msg_ptr, 1);
});
return msg;
}
protected:

View File

@@ -22,7 +22,6 @@
#include "rcl/node.h"
#include "rcutils/logging.h"
#include "rcpputils/filesystem_helper.hpp"
/**
* \def RCLCPP_LOGGING_ENABLED
@@ -76,18 +75,6 @@ RCLCPP_PUBLIC
Logger
get_node_logger(const rcl_node_t * node);
/// Get the current logging directory.
/**
* For more details of how the logging directory is determined,
* see \ref rcl_logging_get_logging_directory.
*
* \returns the logging directory being used.
* \throws rclcpp::exceptions::RCLError if an unexpected error occurs.
*/
RCLCPP_PUBLIC
rcpputils::fs::path
get_logging_directory();
class Logger
{
public:

View File

@@ -1,115 +0,0 @@
// Copyright 2020 Ericsson AB
//
// 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__NETWORK_FLOW_ENDPOINT_HPP_
#define RCLCPP__NETWORK_FLOW_ENDPOINT_HPP_
#include <cstdint>
#include <string>
#include <iostream>
#include "rcl/network_flow_endpoints.h"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
/// Forward declaration
class NetworkFlowEndpoint;
/// Check if two NetworkFlowEndpoint instances are equal
RCLCPP_PUBLIC
bool operator==(const NetworkFlowEndpoint & left, const NetworkFlowEndpoint & right);
/// Check if two NetworkFlowEndpoint instances are not equal
RCLCPP_PUBLIC
bool operator!=(const NetworkFlowEndpoint & left, const NetworkFlowEndpoint & right);
/// Streaming helper for NetworkFlowEndpoint
RCLCPP_PUBLIC
std::ostream & operator<<(std::ostream & os, const NetworkFlowEndpoint & network_flow_endpoint);
/**
* Class describes a network flow endpoint based on the counterpart definition
* in the RMW layer.
*/
class NetworkFlowEndpoint
{
public:
/// Construct from rcl_network_flow_endpoint_t
RCLCPP_PUBLIC
explicit NetworkFlowEndpoint(const rcl_network_flow_endpoint_t & network_flow_endpoint)
: transport_protocol_(
rcl_network_flow_endpoint_get_transport_protocol_string(network_flow_endpoint.
transport_protocol)),
internet_protocol_(
rcl_network_flow_endpoint_get_internet_protocol_string(
network_flow_endpoint.internet_protocol)),
transport_port_(network_flow_endpoint.transport_port),
flow_label_(network_flow_endpoint.flow_label),
dscp_(network_flow_endpoint.dscp),
internet_address_(network_flow_endpoint.internet_address)
{
}
/// Get transport protocol
RCLCPP_PUBLIC
const std::string & transport_protocol() const;
/// Get internet protocol
RCLCPP_PUBLIC
const std::string & internet_protocol() const;
/// Get transport port
RCLCPP_PUBLIC
uint16_t transport_port() const;
/// Get flow label
RCLCPP_PUBLIC
uint32_t flow_label() const;
/// Get DSCP
RCLCPP_PUBLIC
uint8_t dscp() const;
/// Get internet address
RCLCPP_PUBLIC
const std::string & internet_address() const;
/// Compare two NetworkFlowEndpoint instances
friend bool rclcpp::operator==(
const NetworkFlowEndpoint & left,
const NetworkFlowEndpoint & right);
friend bool rclcpp::operator!=(
const NetworkFlowEndpoint & left,
const NetworkFlowEndpoint & right);
/// Streaming helper
friend std::ostream & rclcpp::operator<<(
std::ostream & os,
const NetworkFlowEndpoint & network_flow_endpoint);
private:
std::string transport_protocol_;
std::string internet_protocol_;
uint16_t transport_port_;
uint32_t flow_label_;
uint8_t dscp_;
std::string internet_address_;
};
} // namespace rclcpp
#endif // RCLCPP__NETWORK_FLOW_ENDPOINT_HPP_

View File

@@ -17,7 +17,6 @@
#include <atomic>
#include <condition_variable>
#include <functional>
#include <list>
#include <map>
#include <memory>
@@ -42,8 +41,6 @@
#include "rclcpp/clock.hpp"
#include "rclcpp/context.hpp"
#include "rclcpp/event.hpp"
#include "rclcpp/generic_publisher.hpp"
#include "rclcpp/generic_subscription.hpp"
#include "rclcpp/logger.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/message_memory_strategy.hpp"
@@ -166,7 +163,7 @@ public:
* 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());
* pub = node->create_publisher<MsgT>("chatter", QoS(1).best_effort().volatile());
* {
* rclcpp::QoS custom_qos(KeepLast(10), rmw_qos_profile_sensor_data);
* pub = node->create_publisher<MsgT>("chatter", custom_qos);
@@ -269,55 +266,6 @@ public:
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a GenericPublisher.
/**
* The returned pointer will never be empty, but this function can throw various exceptions, for
* instance when the message's package can not be found on the AMENT_PREFIX_PATH.
*
* \param[in] topic_name Topic name
* \param[in] topic_type Topic type
* \param[in] qos %QoS settings
* \param options %Publisher options.
* Not all publisher options are currently respected, the only relevant options for this
* publisher are `event_callbacks`, `use_default_callbacks`, and `%callback_group`.
* \return Shared pointer to the created generic publisher.
*/
template<typename AllocatorT = std::allocator<void>>
std::shared_ptr<rclcpp::GenericPublisher> create_generic_publisher(
const std::string & topic_name,
const std::string & topic_type,
const rclcpp::QoS & qos,
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options = (
rclcpp::PublisherOptionsWithAllocator<AllocatorT>()
)
);
/// Create and return a GenericSubscription.
/**
* The returned pointer will never be empty, but this function can throw various exceptions, for
* instance when the message's package can not be found on the AMENT_PREFIX_PATH.
*
* \param[in] topic_name Topic name
* \param[in] topic_type Topic type
* \param[in] qos %QoS settings
* \param[in] callback Callback for new messages of serialized form
* \param[in] options %Subscription options.
* Not all subscription options are currently respected, the only relevant options for this
* subscription are `event_callbacks`, `use_default_callbacks`, `ignore_local_publications`, and
* `%callback_group`.
* \return Shared pointer to the created generic subscription.
*/
template<typename AllocatorT = std::allocator<void>>
std::shared_ptr<rclcpp::GenericSubscription> create_generic_subscription(
const std::string & topic_name,
const std::string & topic_type,
const rclcpp::QoS & qos,
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
)
);
/// Declare and initialize a parameter, return the effective value.
/**
* This method is used to declare that a parameter exists on this node.
@@ -357,59 +305,16 @@ public:
* name is invalid.
* \throws rclcpp::exceptions::InvalidParameterValueException if initial
* value fails to be set.
* \throws rclcpp::exceptions::InvalidParameterTypeException
* if the type of the default value or override is wrong.
*/
RCLCPP_PUBLIC
const rclcpp::ParameterValue &
declare_parameter(
const std::string & name,
const rclcpp::ParameterValue & default_value,
const rclcpp::ParameterValue & default_value = rclcpp::ParameterValue(),
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
rcl_interfaces::msg::ParameterDescriptor(),
bool ignore_override = false);
/// Declare and initialize a parameter, return the effective value.
/**
* Same as the previous one, but a default value is not provided and the user
* must provide a parameter override of the correct type.
*
* \param[in] name The name of the parameter.
* \param[in] type Desired type of the parameter, which will enforced at runtime.
* \param[in] parameter_descriptor An optional, custom description for
* the parameter.
* \param[in] ignore_override When `true`, the parameter override is ignored.
* Default to `false`.
* \return A const reference to the value of the parameter.
* \throws Same as the previous overload taking a default value.
* \throws rclcpp::exceptions::InvalidParameterTypeException
* if an override is not provided or the provided override is of the wrong type.
*/
RCLCPP_PUBLIC
const rclcpp::ParameterValue &
declare_parameter(
const std::string & name,
rclcpp::ParameterType type,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
rcl_interfaces::msg::ParameterDescriptor{},
bool ignore_override = false);
/// Declare a parameter
[[deprecated(
"declare_parameter() with only a name is deprecated and will be deleted in the future.\n" \
"If you want to declare a parameter that won't change type without a default value use:\n" \
"`node->declare_parameter<ParameterT>(name)`, where e.g. ParameterT=int64_t.\n\n" \
"If you want to declare a parameter that can dynamically change type use:\n" \
"```\n" \
"rcl_interfaces::msg::ParameterDescriptor descriptor;\n" \
"descriptor.dynamic_typing = true;\n" \
"node->declare_parameter(name, rclcpp::ParameterValue{}, descriptor);\n" \
"```"
)]]
RCLCPP_PUBLIC
const rclcpp::ParameterValue &
declare_parameter(const std::string & name);
/// Declare and initialize a parameter with a type.
/**
* See the non-templated declare_parameter() on this class for details.
@@ -440,18 +345,6 @@ public:
rcl_interfaces::msg::ParameterDescriptor(),
bool ignore_override = false);
/// Declare and initialize a parameter with a type.
/**
* See the non-templated declare_parameter() on this class for details.
*/
template<typename ParameterT>
auto
declare_parameter(
const std::string & name,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
rcl_interfaces::msg::ParameterDescriptor(),
bool ignore_override = false);
/// 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"
@@ -892,9 +785,6 @@ public:
*
* This allows the node developer to control which parameters may be changed.
*
* It is considered bad practice to reject changes for "unknown" parameters as this prevents
* other parts of the node (that may be aware of these parameters) from handling them.
*
* 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

View File

@@ -36,12 +36,10 @@
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/create_client.hpp"
#include "rclcpp/create_generic_publisher.hpp"
#include "rclcpp/create_generic_subscription.hpp"
#include "rclcpp/create_publisher.hpp"
#include "rclcpp/create_service.hpp"
#include "rclcpp/create_subscription.hpp"
#include "rclcpp/create_timer.hpp"
#include "rclcpp/create_subscription.hpp"
#include "rclcpp/detail/resolve_enable_topic_statistics.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/qos.hpp"
@@ -154,43 +152,6 @@ Node::create_service(
group);
}
template<typename AllocatorT>
std::shared_ptr<rclcpp::GenericPublisher>
Node::create_generic_publisher(
const std::string & topic_name,
const std::string & topic_type,
const rclcpp::QoS & qos,
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
{
return rclcpp::create_generic_publisher(
node_topics_,
extend_name_with_sub_namespace(topic_name, this->get_sub_namespace()),
topic_type,
qos,
options
);
}
template<typename AllocatorT>
std::shared_ptr<rclcpp::GenericSubscription>
Node::create_generic_subscription(
const std::string & topic_name,
const std::string & topic_type,
const rclcpp::QoS & qos,
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options)
{
return rclcpp::create_generic_subscription(
node_topics_,
extend_name_with_sub_namespace(topic_name, this->get_sub_namespace()),
topic_type,
qos,
std::move(callback),
options
);
}
template<typename ParameterT>
auto
Node::declare_parameter(
@@ -211,24 +172,6 @@ Node::declare_parameter(
}
}
template<typename ParameterT>
auto
Node::declare_parameter(
const std::string & name,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
bool ignore_override)
{
// get advantage of parameter value template magic to get
// the correct rclcpp::ParameterType from ParameterT
rclcpp::ParameterValue value{ParameterT{}};
return this->declare_parameter(
name,
value.get_type(),
parameter_descriptor,
ignore_override
).get<ParameterT>();
}
template<typename ParameterT>
std::vector<ParameterT>
Node::declare_parameters(

View File

@@ -103,42 +103,13 @@ public:
virtual
~NodeParameters();
// This is overriding a deprecated method, so we need to ignore the deprecation warning here.
// Users of the method will still get a warning!
#ifndef _WIN32
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
[[deprecated(RCLCPP_INTERNAL_NODE_PARAMETERS_INTERFACE_DEPRECATE_DECLARE)]]
RCLCPP_PUBLIC
const rclcpp::ParameterValue &
declare_parameter(const std::string & name) override;
#ifndef _WIN32
# pragma GCC diagnostic pop
#else
# pragma warning(pop)
#endif
RCLCPP_PUBLIC
const rclcpp::ParameterValue &
declare_parameter(
const std::string & name,
const rclcpp::ParameterValue & default_value,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
rcl_interfaces::msg::ParameterDescriptor{},
bool ignore_override = false) override;
RCLCPP_PUBLIC
const rclcpp::ParameterValue &
declare_parameter(
const std::string & name,
rclcpp::ParameterType type,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
rcl_interfaces::msg::ParameterDescriptor(),
bool ignore_override = false) override;
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
bool ignore_override) override;
RCLCPP_PUBLIC
void

View File

@@ -45,17 +45,6 @@ struct OnSetParametersCallbackHandle
OnParametersSetCallbackType callback;
};
#define RCLCPP_INTERNAL_NODE_PARAMETERS_INTERFACE_DEPRECATE_DECLARE \
"declare_parameter() with only a name is deprecated and will be deleted in the future.\n" \
"If you want to declare a parameter that won't change type without a default value use:\n" \
"`node_params->declare_parameter(name, type)`, with e.g. type=rclcpp::PARAMETER_INTEGER.\n\n" \
"If you want to declare a parameter that can dynamically change type use:\n" \
"```\n" \
"rcl_interfaces::msg::ParameterDescriptor descriptor;\n" \
"descriptor.dynamic_typing = true;\n" \
"node_params->declare_parameter(name, rclcpp::ParameterValue{}, descriptor);\n" \
"```"
/// Pure virtual interface class for the NodeParameters part of the Node API.
class NodeParametersInterface
{
@@ -66,15 +55,6 @@ public:
virtual
~NodeParametersInterface() = default;
/// Declare a parameter.
/**
* \sa rclcpp::Node::declare_parameter
*/
[[deprecated(RCLCPP_INTERNAL_NODE_PARAMETERS_INTERFACE_DEPRECATE_DECLARE)]]
virtual
const rclcpp::ParameterValue &
declare_parameter(const std::string & name) = 0;
/// Declare and initialize a parameter.
/**
* \sa rclcpp::Node::declare_parameter
@@ -84,21 +64,7 @@ public:
const rclcpp::ParameterValue &
declare_parameter(
const std::string & name,
const rclcpp::ParameterValue & default_value,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
rcl_interfaces::msg::ParameterDescriptor(),
bool ignore_override = false) = 0;
/// Declare a parameter.
/**
* \sa rclcpp::Node::declare_parameter
*/
RCLCPP_PUBLIC
virtual
const rclcpp::ParameterValue &
declare_parameter(
const std::string & name,
rclcpp::ParameterType type,
const rclcpp::ParameterValue & default_value = rclcpp::ParameterValue(),
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
rcl_interfaces::msg::ParameterDescriptor(),
bool ignore_override = false) = 0;
@@ -130,7 +96,7 @@ public:
std::vector<rcl_interfaces::msg::SetParametersResult>
set_parameters(const std::vector<rclcpp::Parameter> & parameters) = 0;
/// Set one or more parameters, all at once.
/// Set and initialize a parameter, all at once.
/**
* \sa rclcpp::Node::set_parameters_atomically
*/

View File

@@ -48,8 +48,7 @@ public:
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock,
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters,
const rclcpp::QoS & qos = rclcpp::RosoutQoS(),
bool use_clock_thread = true
const rclcpp::QoS & qos = rclcpp::RosoutQoS()
);
RCLCPP_PUBLIC

View File

@@ -47,7 +47,6 @@ public:
* - start_parameter_services = true
* - start_parameter_event_publisher = true
* - clock_qos = rclcpp::ClockQoS()
* - use_clock_thread = true
* - rosout_qos = rclcpp::RosoutQoS()
* - parameter_event_qos = rclcpp::ParameterEventQoS
* - with history setting and depth from rmw_qos_profile_parameter_events
@@ -259,20 +258,6 @@ public:
NodeOptions &
clock_qos(const rclcpp::QoS & clock_qos);
/// Return the use_clock_thread flag.
RCLCPP_PUBLIC
bool
use_clock_thread() const;
/// Set the use_clock_thread flag, return this for parameter idiom.
/**
* If true, a dedicated thread will be used to subscribe to "/clock" topic.
*/
RCLCPP_PUBLIC
NodeOptions &
use_clock_thread(bool use_clock_thread);
/// Return a reference to the parameter_event_qos QoS.
RCLCPP_PUBLIC
const rclcpp::QoS &
@@ -399,8 +384,6 @@ private:
rclcpp::QoS clock_qos_ = rclcpp::ClockQoS();
bool use_clock_thread_ {true};
rclcpp::QoS parameter_event_qos_ = rclcpp::ParameterEventsQoS(
rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events)
);

View File

@@ -15,8 +15,6 @@
#ifndef RCLCPP__PARAMETER_CLIENT_HPP_
#define RCLCPP__PARAMETER_CLIENT_HPP_
#include <functional>
#include <future>
#include <memory>
#include <string>
#include <utility>
@@ -31,14 +29,11 @@
#include "rcl_interfaces/srv/list_parameters.hpp"
#include "rcl_interfaces/srv/set_parameters.hpp"
#include "rcl_interfaces/srv/set_parameters_atomically.hpp"
#include "rcl_yaml_param_parser/parser.h"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/executors.hpp"
#include "rclcpp/create_subscription.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/parameter_map.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rmw/rmw.h"
@@ -125,14 +120,6 @@ public:
void(std::shared_future<std::vector<rclcpp::Parameter>>)
> callback = nullptr);
RCLCPP_PUBLIC
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>>
describe_parameters(
const std::vector<std::string> & names,
std::function<
void(std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>>)
> callback = nullptr);
RCLCPP_PUBLIC
std::shared_future<std::vector<rclcpp::ParameterType>>
get_parameter_types(
@@ -157,42 +144,6 @@ public:
void(std::shared_future<rcl_interfaces::msg::SetParametersResult>)
> callback = nullptr);
/// Delete several parameters at once.
/**
* This function behaves like command-line tool `ros2 param delete` would.
*
* \param parameters_names vector of parameters names
* \return the future of the set_parameter service used to delete the parameters
*/
RCLCPP_PUBLIC
std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>
delete_parameters(
const std::vector<std::string> & parameters_names);
/// Load parameters from yaml file.
/**
* This function behaves like command-line tool `ros2 param load` would.
*
* \param yaml_filename the full name of the yaml file
* \return the future of the set_parameter service used to load the parameters
*/
RCLCPP_PUBLIC
std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>
load_parameters(
const std::string & yaml_filename);
/// Load parameters from parameter map.
/**
* This function filters the parameters to be set based on the node name.
*
* \param yaml_filename the full name of the yaml file
* \return the future of the set_parameter service used to load the parameters
* \throw InvalidParametersException if there is no parameter to set
*/
RCLCPP_PUBLIC
std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>
load_parameters(const rclcpp::ParameterMap & parameter_map);
RCLCPP_PUBLIC
std::shared_future<rcl_interfaces::msg::ListParametersResult>
list_parameters(
@@ -381,17 +332,9 @@ public:
qos_profile);
}
template<typename RepT = int64_t, typename RatioT = std::milli>
RCLCPP_PUBLIC
std::vector<rclcpp::Parameter>
get_parameters(
const std::vector<std::string> & parameter_names,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return get_parameters(
parameter_names,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
get_parameters(const std::vector<std::string> & parameter_names);
RCLCPP_PUBLIC
bool
@@ -435,107 +378,23 @@ public:
);
}
template<typename RepT = int64_t, typename RatioT = std::milli>
std::vector<rcl_interfaces::msg::ParameterDescriptor>
describe_parameters(
const std::vector<std::string> & parameter_names,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return describe_parameters(
parameter_names,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
template<typename RepT = int64_t, typename RatioT = std::milli>
RCLCPP_PUBLIC
std::vector<rclcpp::ParameterType>
get_parameter_types(
const std::vector<std::string> & parameter_names,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return get_parameter_types(
parameter_names,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
get_parameter_types(const std::vector<std::string> & parameter_names);
template<typename RepT = int64_t, typename RatioT = std::milli>
RCLCPP_PUBLIC
std::vector<rcl_interfaces::msg::SetParametersResult>
set_parameters(
const std::vector<rclcpp::Parameter> & parameters,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return set_parameters(
parameters,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
set_parameters(const std::vector<rclcpp::Parameter> & parameters);
template<typename RepT = int64_t, typename RatioT = std::milli>
RCLCPP_PUBLIC
rcl_interfaces::msg::SetParametersResult
set_parameters_atomically(
const std::vector<rclcpp::Parameter> & parameters,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return set_parameters_atomically(
parameters,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
set_parameters_atomically(const std::vector<rclcpp::Parameter> & parameters);
/// Delete several parameters at once.
/**
* This function behaves like command-line tool `ros2 param delete` would.
*
* \param parameters_names vector of parameters names
* \param timeout for the spin used to make it synchronous
* \return the future of the set_parameter service used to delete the parameters
*/
template<typename RepT = int64_t, typename RatioT = std::milli>
std::vector<rcl_interfaces::msg::SetParametersResult>
delete_parameters(
const std::vector<std::string> & parameters_names,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return delete_parameters(
parameters_names,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
/// Load parameters from yaml file.
/**
* This function behaves like command-line tool `ros2 param load` would.
*
* \param yaml_filename the full name of the yaml file
* \param timeout for the spin used to make it synchronous
* \return the future of the set_parameter service used to load the parameters
*/
template<typename RepT = int64_t, typename RatioT = std::milli>
std::vector<rcl_interfaces::msg::SetParametersResult>
load_parameters(
const std::string & yaml_filename,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return load_parameters(
yaml_filename,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
template<typename RepT = int64_t, typename RatioT = std::milli>
RCLCPP_PUBLIC
rcl_interfaces::msg::ListParametersResult
list_parameters(
const std::vector<std::string> & parameter_prefixes,
uint64_t depth,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return list_parameters(
parameter_prefixes,
depth,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
uint64_t depth);
template<typename CallbackT>
typename rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr
@@ -578,56 +437,6 @@ public:
return async_parameters_client_->wait_for_service(timeout);
}
protected:
RCLCPP_PUBLIC
std::vector<rclcpp::Parameter>
get_parameters(
const std::vector<std::string> & parameter_names,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
std::vector<rcl_interfaces::msg::ParameterDescriptor>
describe_parameters(
const std::vector<std::string> & parameter_names,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
std::vector<rclcpp::ParameterType>
get_parameter_types(
const std::vector<std::string> & parameter_names,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
std::vector<rcl_interfaces::msg::SetParametersResult>
set_parameters(
const std::vector<rclcpp::Parameter> & parameters,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
std::vector<rcl_interfaces::msg::SetParametersResult>
delete_parameters(
const std::vector<std::string> & parameters_names,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
std::vector<rcl_interfaces::msg::SetParametersResult>
load_parameters(
const std::string & yaml_filename,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
rcl_interfaces::msg::SetParametersResult
set_parameters_atomically(
const std::vector<rclcpp::Parameter> & parameters,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
rcl_interfaces::msg::ListParametersResult
list_parameters(
const std::vector<std::string> & parameter_prefixes,
uint64_t depth,
std::chrono::nanoseconds timeout);
private:
rclcpp::Executor::SharedPtr executor_;
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface_;

View File

@@ -1,338 +0,0 @@
// Copyright 2019 Intel Corporation
//
// 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__PARAMETER_EVENT_HANDLER_HPP_
#define RCLCPP__PARAMETER_EVENT_HANDLER_HPP_
#include <list>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "rclcpp/create_subscription.hpp"
#include "rclcpp/node_interfaces/get_node_base_interface.hpp"
#include "rclcpp/node_interfaces/get_node_topics_interface.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/subscription.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rcl_interfaces/msg/parameter_event.hpp"
namespace rclcpp
{
struct ParameterCallbackHandle
{
RCLCPP_SMART_PTR_DEFINITIONS(ParameterCallbackHandle)
using ParameterCallbackType = std::function<void (const rclcpp::Parameter &)>;
std::string parameter_name;
std::string node_name;
ParameterCallbackType callback;
};
struct ParameterEventCallbackHandle
{
RCLCPP_SMART_PTR_DEFINITIONS(ParameterEventCallbackHandle)
using ParameterEventCallbackType =
std::function<void (const rcl_interfaces::msg::ParameterEvent &)>;
ParameterEventCallbackType callback;
};
/// A class used to "handle" (monitor and respond to) changes to parameters.
/**
* The ParameterEventHandler class allows for the monitoring of changes to node parameters,
* either a node's own parameters or parameters owned by other nodes in the system.
* Multiple parameter callbacks can be set and will be invoked when the specified parameter
* changes.
*
* The first step is to instantiate a ParameterEventHandler, providing a ROS node to use
* to create any required subscriptions:
*
* auto param_handler = std::make_shared<rclcpp::ParameterEventHandler>(node);
*
* Next, you can supply a callback to the add_parameter_callback method, as follows:
*
* auto cb1 = [&node](const rclcpp::Parameter & p) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb1: Received an update to parameter \"%s\" of type %s: \"%ld\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_int());
* };
* auto handle1 = param_handler->add_parameter_callback("an_int_param", cb1);
*
* In this case, we didn't supply a node name (the third, optional, parameter) so the
* default will be to monitor for changes to the "an_int_param" parameter associated with
* the ROS node supplied in the ParameterEventHandler constructor.
* The callback, a lambda function in this case, simply prints out the value of the parameter.
*
* You may also monitor for changes to parameters in other nodes by supplying the node
* name to add_parameter_callback:
*
* auto cb2 = [&node](const rclcpp::Parameter & p) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb2: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_string().c_str());
* };
* auto handle2 = param_handler->add_parameter_callback(
* "some_remote_param_name", cb2, "some_remote_node_name");
*
* In this case, the callback will be invoked whenever "some_remote_param_name" changes
* on remote node "some_remote_node_name".
*
* To remove a parameter callback, call remove_parameter_callback, passing the handle returned
* from add_parameter_callback:
*
* param_handler->remove_parameter_callback(handle2);
*
* You can also monitor for *all* parameter changes, using add_parameter_event_callback.
* In this case, the callback will be invoked whenever any parameter changes in the system.
* You are likely interested in a subset of these parameter changes, so in the callback it
* is convenient to use a regular expression on the node names or namespaces of interest.
* For example:
*
* auto cb3 =
* [fqn, remote_param_name, &node](const rcl_interfaces::msg::ParameterEvent & event) {
* // Look for any updates to parameters in "/a_namespace" as well as any parameter changes
* // to our own node ("this_node")
* std::regex re("(/a_namespace/.*)|(/this_node)");
* if (regex_match(event.node, re)) {
* // Now that we know the event matches the regular expression we scanned for, we can
* // use 'get_parameter_from_event' to get a specific parameter name that we're looking for
* rclcpp::Parameter p;
* if (rclcpp::ParameterEventsSubscriber::get_parameter_from_event(
* event, p, remote_param_name, fqn))
* {
* RCLCPP_INFO(
* node->get_logger(),
* "cb3: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_string().c_str());
* }
*
* // You can also use 'get_parameter*s*_from_event' to enumerate all changes that came
* // in on this event
* auto params = rclcpp::ParameterEventsSubscriber::get_parameters_from_event(event);
* for (auto & p : params) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb3: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.value_to_string().c_str());
* }
* }
* };
* auto handle3 = param_handler->add_parameter_event_callback(cb3);
*
* For both parameter callbacks and parameter event callbacks, when multiple callbacks are added,
* the callbacks are invoked last-in, first-called order (LIFO).
*
* To remove a parameter event callback, use:
*
* param_handler->remove_event_parameter_callback(handle);
*/
class ParameterEventHandler
{
public:
/// Construct a parameter events monitor.
/**
* \param[in] node The node to use to create any required subscribers.
* \param[in] qos The QoS settings to use for any subscriptions.
*/
template<typename NodeT>
ParameterEventHandler(
NodeT node,
const rclcpp::QoS & qos =
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events)))
{
node_base_ = rclcpp::node_interfaces::get_node_base_interface(node);
auto node_topics = rclcpp::node_interfaces::get_node_topics_interface(node);
event_subscription_ = rclcpp::create_subscription<rcl_interfaces::msg::ParameterEvent>(
node_topics, "/parameter_events", qos,
std::bind(&ParameterEventHandler::event_callback, this, std::placeholders::_1));
}
using ParameterEventCallbackType =
ParameterEventCallbackHandle::ParameterEventCallbackType;
/// Set a callback for all parameter events.
/**
* This function may be called multiple times to set multiple parameter event callbacks.
*
* \param[in] callback Function callback to be invoked on parameter updates.
* \returns A handle used to refer to the callback.
*/
RCLCPP_PUBLIC
ParameterEventCallbackHandle::SharedPtr
add_parameter_event_callback(
ParameterEventCallbackType callback);
/// Remove parameter event callback registered with add_parameter_event_callback.
/**
* \param[in] callback_handle Handle of the callback to remove.
*/
RCLCPP_PUBLIC
void
remove_parameter_event_callback(
ParameterEventCallbackHandle::SharedPtr callback_handle);
using ParameterCallbackType = ParameterCallbackHandle::ParameterCallbackType;
/// Add a callback for a specified parameter.
/**
* If a node_name is not provided, defaults to the current node.
*
* \param[in] parameter_name Name of parameter to monitor.
* \param[in] callback Function callback to be invoked upon parameter update.
* \param[in] node_name Name of node which hosts the parameter.
* \returns A handle used to refer to the callback.
*/
RCLCPP_PUBLIC
ParameterCallbackHandle::SharedPtr
add_parameter_callback(
const std::string & parameter_name,
ParameterCallbackType callback,
const std::string & node_name = "");
/// Remove a parameter callback registered with add_parameter_callback.
/**
* The parameter name and node name are inspected from the callback handle. The callback handle
* is erased from the list of callback handles on the {parameter_name, node_name} in the map.
* An error is thrown if the handle does not exist and/or was already removed.
*
* \param[in] callback_handle Handle of the callback to remove.
*/
RCLCPP_PUBLIC
void
remove_parameter_callback(
ParameterCallbackHandle::SharedPtr callback_handle);
/// Get an rclcpp::Parameter from a parameter event.
/**
* If a node_name is not provided, defaults to the current node.
*
* \param[in] event Event msg to be inspected.
* \param[out] parameter Reference to rclcpp::Parameter to be assigned.
* \param[in] parameter_name Name of parameter.
* \param[in] node_name Name of node which hosts the parameter.
* \returns Output parameter is set with requested parameter info and returns true if
* requested parameter name and node is in event. Otherwise, returns false.
*/
RCLCPP_PUBLIC
static bool
get_parameter_from_event(
const rcl_interfaces::msg::ParameterEvent & event,
rclcpp::Parameter & parameter,
const std::string parameter_name,
const std::string node_name = "");
/// Get an rclcpp::Parameter from parameter event
/**
* If a node_name is not provided, defaults to the current node.
*
* The user is responsible to check if the returned parameter has been properly assigned.
* By default, if the requested parameter is not found in the event, the returned parameter
* has parameter value of type rclcpp::PARAMETER_NOT_SET.
*
* \param[in] event Event msg to be inspected.
* \param[in] parameter_name Name of parameter.
* \param[in] node_name Name of node which hosts the parameter.
* \returns The resultant rclcpp::Parameter from the event.
*/
RCLCPP_PUBLIC
static rclcpp::Parameter
get_parameter_from_event(
const rcl_interfaces::msg::ParameterEvent & event,
const std::string parameter_name,
const std::string node_name = "");
/// Get all rclcpp::Parameter values from a parameter event
/**
* \param[in] event Event msg to be inspected.
* \returns A vector rclcpp::Parameter values from the event.
*/
RCLCPP_PUBLIC
static std::vector<rclcpp::Parameter>
get_parameters_from_event(
const rcl_interfaces::msg::ParameterEvent & event);
using CallbacksContainerType = std::list<ParameterCallbackHandle::WeakPtr>;
protected:
/// Callback for parameter events subscriptions.
RCLCPP_PUBLIC
void
event_callback(const rcl_interfaces::msg::ParameterEvent & event);
// Utility function for resolving node path.
std::string resolve_path(const std::string & path);
// Node interface used for base functionality
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> node_base_;
// *INDENT-OFF* Uncrustify doesn't handle indented public/private labels
// Hash function for string pair required in std::unordered_map
// See: https://stackoverflow.com/questions/35985960/c-why-is-boosthash-combine-the-best-way-to-combine-hash-values
class StringPairHash
{
public:
template<typename T>
inline void hash_combine(std::size_t & seed, const T & v) const
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
inline size_t operator()(const std::pair<std::string, std::string> & s) const
{
size_t seed = 0;
hash_combine(seed, s.first);
hash_combine(seed, s.second);
return seed;
}
};
// *INDENT-ON*
// Map container for registered parameters
std::unordered_map<
std::pair<std::string, std::string>,
CallbacksContainerType,
StringPairHash
> parameter_callbacks_;
rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr event_subscription_;
std::list<ParameterEventCallbackHandle::WeakPtr> event_callbacks_;
std::recursive_mutex mutex_;
};
} // namespace rclcpp
#endif // RCLCPP__PARAMETER_EVENT_HANDLER_HPP_

View File

@@ -37,7 +37,7 @@ public:
RCLCPP_SMART_PTR_DEFINITIONS(ParameterEventsFilter)
enum class EventType {NEW, DELETED, CHANGED}; ///< An enum for the type of event.
/// Used for the listed results
using EventPair = std::pair<EventType, const rcl_interfaces::msg::Parameter *>;
using EventPair = std::pair<EventType, rcl_interfaces::msg::Parameter *>;
/// Construct a filtered view of a parameter event.
/**
@@ -60,7 +60,7 @@ public:
*/
RCLCPP_PUBLIC
ParameterEventsFilter(
std::shared_ptr<const rcl_interfaces::msg::ParameterEvent> event,
rcl_interfaces::msg::ParameterEvent::SharedPtr event,
const std::vector<std::string> & names,
const std::vector<EventType> & types);
@@ -74,7 +74,7 @@ public:
private:
// access only allowed via const accessor.
std::vector<EventPair> result_; ///< Storage of the resultant vector
std::shared_ptr<const rcl_interfaces::msg::ParameterEvent> event_; ///< Keep event in scope
rcl_interfaces::msg::ParameterEvent::SharedPtr event_; ///< Keep event in scope
};
} // namespace rclcpp

View File

@@ -0,0 +1,234 @@
// Copyright 2019 Intel Corporation
//
// 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__PARAMETER_EVENTS_SUBSCRIBER_HPP_
#define RCLCPP__PARAMETER_EVENTS_SUBSCRIBER_HPP_
#include <list>
#include <memory>
#include <string>
#include <utility>
#include <unordered_map>
#include <vector>
#include "rcl_interfaces/msg/parameter_event.hpp"
#include "rclcpp/create_subscription.hpp"
#include "rclcpp/node_interfaces/get_node_base_interface.hpp"
#include "rclcpp/node_interfaces/get_node_logging_interface.hpp"
#include "rclcpp/node_interfaces/get_node_topics_interface.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_logging_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/subscription.hpp"
namespace rclcpp
{
struct ParameterCallbackHandle
{
RCLCPP_SMART_PTR_DEFINITIONS(ParameterCallbackHandle)
using ParameterCallbackType = std::function<void (const rclcpp::Parameter &)>;
std::string parameter_name;
std::string node_name;
ParameterCallbackType callback;
};
struct ParameterEventCallbackHandle
{
RCLCPP_SMART_PTR_DEFINITIONS(ParameterEventCallbackHandle)
using ParameterEventCallbackType =
std::function<void (const rcl_interfaces::msg::ParameterEvent::SharedPtr &)>;
ParameterEventCallbackType callback;
};
class ParameterEventsSubscriber
{
public:
/// Construct a subscriber to parameter events
template<typename NodeT>
ParameterEventsSubscriber(
NodeT node,
const rclcpp::QoS & qos =
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events)))
{
node_base_ = rclcpp::node_interfaces::get_node_base_interface(node);
node_logging_ = rclcpp::node_interfaces::get_node_logging_interface(node);
auto node_topics = rclcpp::node_interfaces::get_node_topics_interface(node);
event_subscription_ = rclcpp::create_subscription<rcl_interfaces::msg::ParameterEvent>(
node_topics, "/parameter_events", qos,
std::bind(&ParameterEventsSubscriber::event_callback, this, std::placeholders::_1));
}
using ParameterEventCallbackType =
ParameterEventCallbackHandle::ParameterEventCallbackType;
/// Set a custom callback for parameter events.
/**
* Multiple callbacks are allowed.
*
* \param[in] callback Function callback to be evaluated on event.
*/
RCLCPP_PUBLIC
ParameterEventCallbackHandle::SharedPtr
add_parameter_event_callback(
ParameterEventCallbackType callback);
/// Remove parameter event callback.
/**
* Calling this function will set the event callback to nullptr.
*/
RCLCPP_PUBLIC
void
remove_parameter_event_callback(
const ParameterEventCallbackHandle * const handle);
using ParameterCallbackType = ParameterCallbackHandle::ParameterCallbackType;
/// Add a custom callback for a specified parameter.
/**
* If a node_name is not provided, defaults to the current node.
*
* \param[in] parameter_name Name of parameter.
* \param[in] callback Function callback to be evaluated upon parameter event.
* \param[in] node_name Name of node which hosts the parameter.
*/
RCLCPP_PUBLIC
ParameterCallbackHandle::SharedPtr
add_parameter_callback(
const std::string & parameter_name,
ParameterCallbackType callback,
const std::string & node_name = "");
/// Remove a custom callback for a specified parameter given its callback handle.
/**
* The parameter name and node name are inspected from the callback handle. The callback handle
* is erased from the list of callback handles on the {parameter_name, node_name} in the map.
* An error is thrown if the handle does not exist and/or was already removed.
*
* \param[in] handle Pointer to callback handle to be removed.
*/
RCLCPP_PUBLIC
void
remove_parameter_callback(
const ParameterCallbackHandle * const handle);
/// Get a rclcpp::Parameter from parameter event, return true if parameter name & node in event.
/**
* If a node_name is not provided, defaults to the current node.
*
* \param[in] event Event msg to be inspected.
* \param[out] parameter Reference to rclcpp::Parameter to be assigned.
* \param[in] parameter_name Name of parameter.
* \param[in] node_name Name of node which hosts the parameter.
* \returns true if requested parameter name & node is in event, false otherwise
*/
RCLCPP_PUBLIC
static bool
get_parameter_from_event(
const rcl_interfaces::msg::ParameterEvent & event,
rclcpp::Parameter & parameter,
const std::string parameter_name,
const std::string node_name = "");
/// Get a rclcpp::Parameter from parameter event
/**
* If a node_name is not provided, defaults to the current node.
*
* The user is responsible to check if the returned parameter has been properly assigned.
* By default, if the requested parameter is not found in the event, the returned parameter
* has parameter value of type rclcpp::PARAMETER_NOT_SET.
*
* \param[in] event Event msg to be inspected.
* \param[in] parameter_name Name of parameter.
* \param[in] node_name Name of node which hosts the parameter.
* \returns The resultant rclcpp::Parameter from the event
*/
RCLCPP_PUBLIC
static rclcpp::Parameter
get_parameter_from_event(
const rcl_interfaces::msg::ParameterEvent & event,
const std::string parameter_name,
const std::string node_name = "");
/// Get all rclcpp::Parameter values from a parameter event
/**
* \param[in] event Event msg to be inspected.
* \returns A vector rclcpp::Parameter values from the event
*/
RCLCPP_PUBLIC
static std::vector<rclcpp::Parameter>
get_parameters_from_event(
const rcl_interfaces::msg::ParameterEvent & event);
using CallbacksContainerType = std::list<ParameterCallbackHandle::WeakPtr>;
protected:
/// Callback for parameter events subscriptions.
void
event_callback(const rcl_interfaces::msg::ParameterEvent::SharedPtr event);
// Utility function for resolving node path.
std::string resolve_path(const std::string & path);
// Node Interfaces used for base and logging.
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> node_base_;
std::shared_ptr<rclcpp::node_interfaces::NodeLoggingInterface> node_logging_;
// *INDENT-OFF* Uncrustify doesn't handle indented public/private labels
// Hash function for string pair required in std::unordered_map
// See: https://stackoverflow.com/questions/35985960/c-why-is-boosthash-combine-the-best-way-to-combine-hash-values
class StringPairHash
{
public:
template<typename T>
inline void hash_combine(std::size_t & seed, const T & v) const
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
inline size_t operator()(const std::pair<std::string, std::string> & s) const
{
size_t seed = 0;
hash_combine(seed, s.first);
hash_combine(seed, s.second);
return seed;
}
};
// *INDENT-ON*
// Map container for registered parameters.
std::unordered_map<
std::pair<std::string, std::string>,
CallbacksContainerType,
StringPairHash
> parameter_callbacks_;
rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr event_subscription_;
std::list<ParameterEventCallbackHandle::WeakPtr> event_callbacks_;
std::recursive_mutex mutex_;
};
} // namespace rclcpp
#endif // RCLCPP__PARAMETER_EVENTS_SUBSCRIBER_HPP_

View File

@@ -15,7 +15,6 @@
#ifndef RCLCPP__PARAMETER_MAP_HPP_
#define RCLCPP__PARAMETER_MAP_HPP_
#include <rcl_yaml_param_parser/parser.h>
#include <rcl_yaml_param_parser/types.h>
#include <string>
@@ -49,14 +48,6 @@ RCLCPP_PUBLIC
ParameterValue
parameter_value_from(const rcl_variant_t * const c_value);
/// Get the ParameterMap from a yaml file.
/// \param[in] yaml_filename full name of the yaml file.
/// \returns an instance of a parameter map
/// \throws from rcl error of rcl_parse_yaml_file()
RCLCPP_PUBLIC
ParameterMap
parameter_map_from_yaml_file(const std::string & yaml_filename);
} // namespace rclcpp
#endif // RCLCPP__PARAMETER_MAP_HPP_

View File

@@ -40,8 +40,6 @@
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
#include "tracetools/tracetools.h"
namespace rclcpp
{
@@ -263,7 +261,7 @@ public:
if (this->can_loan_messages()) {
// we release the ownership from the rclpp::LoanedMessage instance
// and let the middleware clean up the memory.
this->do_loaned_message_publish(std::move(loaned_msg.release()));
this->do_loaned_message_publish(loaned_msg.release());
} else {
// we don't release the ownership, let the middleware copy the ros message
// and thus the destructor of rclcpp::LoanedMessage cleans up the memory.
@@ -281,10 +279,6 @@ protected:
void
do_inter_process_publish(const MessageT & msg)
{
TRACEPOINT(
rclcpp_publish,
static_cast<const void *>(publisher_handle_.get()),
static_cast<const void *>(&msg));
auto status = rcl_publish(publisher_handle_.get(), &msg, nullptr);
if (RCL_RET_PUBLISHER_INVALID == status) {
@@ -316,9 +310,9 @@ protected:
}
void
do_loaned_message_publish(std::unique_ptr<MessageT, std::function<void(MessageT *)>> msg)
do_loaned_message_publish(MessageT * msg)
{
auto status = rcl_publish_loaned_message(publisher_handle_.get(), msg.get(), nullptr);
auto status = rcl_publish_loaned_message(publisher_handle_.get(), msg, nullptr);
if (RCL_RET_PUBLISHER_INVALID == status) {
rcl_reset_error(); // next call will reset error message if not context

View File

@@ -28,7 +28,6 @@
#include "rcl/publisher.h"
#include "rclcpp/macros.hpp"
#include "rclcpp/network_flow_endpoint.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/type_support_decl.hpp"
@@ -194,15 +193,6 @@ public:
uint64_t intra_process_publisher_id,
IntraProcessManagerSharedPtr ipm);
/// Get network flow endpoints
/**
* Describes network flow endpoints that this publisher is sending messages out on
* \return vector of NetworkFlowEndpoint
*/
RCLCPP_PUBLIC
std::vector<rclcpp::NetworkFlowEndpoint>
get_network_flow_endpoints() const;
protected:
template<typename EventCallbackT>
void

View File

@@ -45,11 +45,6 @@ struct PublisherOptionsBase
/// Whether or not to use default callbacks when user doesn't supply any in event_callbacks
bool use_default_callbacks = true;
/// Require middleware to generate unique network flow endpoints
/// Disabled by default
rmw_unique_network_flow_endpoints_requirement_t require_unique_network_flow_endpoints =
RMW_UNIQUE_NETWORK_FLOW_ENDPOINTS_NOT_REQUIRED;
/// Callback group in which the waitable items from the publisher should be placed.
std::shared_ptr<rclcpp::CallbackGroup> callback_group;
@@ -85,8 +80,6 @@ struct PublisherOptionsWithAllocator : public PublisherOptionsBase
auto message_alloc = std::make_shared<MessageAllocatorT>(*this->get_allocator().get());
result.allocator = rclcpp::allocator::get_rcl_allocator<MessageT>(*message_alloc);
result.qos = qos.get_rmw_qos_profile();
result.rmw_publisher_options.require_unique_network_flow_endpoints =
this->require_unique_network_flow_endpoints;
// Apply payload to rcl_publisher_options if necessary.
if (rmw_implementation_payload && rmw_implementation_payload->has_been_customized()) {
@@ -102,7 +95,12 @@ struct PublisherOptionsWithAllocator : public PublisherOptionsBase
get_allocator() const
{
if (!this->allocator) {
return std::make_shared<Allocator>();
// TODO(wjwwood): I would like to use the commented line instead, but
// cppcheck 1.89 fails with:
// Syntax Error: AST broken, binary operator '>' doesn't have two operands.
// return std::make_shared<Allocator>();
std::shared_ptr<Allocator> tmp(new Allocator());
return tmp;
}
return this->allocator;
}

View File

@@ -18,7 +18,6 @@
#include <string>
#include "rclcpp/duration.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rcl/logging_rosout.h"
#include "rmw/incompatible_qos_events_statuses.h"
@@ -31,45 +30,6 @@ namespace rclcpp
RCLCPP_PUBLIC
std::string qos_policy_name_from_kind(rmw_qos_policy_kind_t policy_kind);
enum class HistoryPolicy
{
KeepLast = RMW_QOS_POLICY_HISTORY_KEEP_LAST,
KeepAll = RMW_QOS_POLICY_HISTORY_KEEP_ALL,
SystemDefault = RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT,
Unknown = RMW_QOS_POLICY_HISTORY_UNKNOWN,
};
enum class ReliabilityPolicy
{
BestEffort = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT,
Reliable = RMW_QOS_POLICY_RELIABILITY_RELIABLE,
SystemDefault = RMW_QOS_POLICY_RELIABILITY_SYSTEM_DEFAULT,
Unknown = RMW_QOS_POLICY_RELIABILITY_UNKNOWN,
};
enum class DurabilityPolicy
{
Volatile = RMW_QOS_POLICY_DURABILITY_VOLATILE,
TransientLocal = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL,
SystemDefault = RMW_QOS_POLICY_DURABILITY_SYSTEM_DEFAULT,
Unknown = RMW_QOS_POLICY_DURABILITY_UNKNOWN,
};
enum class LivelinessPolicy
{
Automatic = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC,
ManualByTopic = RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC,
SystemDefault = RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT,
Unknown = RMW_QOS_POLICY_LIVELINESS_UNKNOWN,
};
enum class QoSCompatibility
{
Ok = RMW_QOS_COMPATIBILITY_OK,
Warning = RMW_QOS_COMPATIBILITY_WARNING,
Error = RMW_QOS_COMPATIBILITY_ERROR,
};
/// QoS initialization values, cannot be created directly, use KeepAll or KeepLast instead.
struct RCLCPP_PUBLIC QoSInitialization
{
@@ -98,32 +58,10 @@ struct RCLCPP_PUBLIC KeepLast : public rclcpp::QoSInitialization
};
/// Encapsulation of Quality of Service settings.
/**
* Quality of Service settings control the behavior of publishers, subscriptions,
* and other entities, and includes things like how data is sent or resent,
* how data is buffered on the publishing and subscribing side, and other things.
* See:
* <a href="https://docs.ros.org/en/rolling/Concepts/About-Quality-of-Service-Settings.html">
* https://docs.ros.org/en/rolling/Concepts/About-Quality-of-Service-Settings.html
* </a>
*/
class RCLCPP_PUBLIC QoS
{
public:
/// Create a QoS by specifying only the history policy and history depth.
/**
* When using the default initial profile, the defaults will include:
*
* - \link rclcpp::ReliabilityPolicy::Reliable ReliabilityPolicy::Reliable\endlink
* - \link rclcpp::DurabilityPolicy::Volatile DurabilityPolicy::Volatile\endlink
*
* See rmw_qos_profile_default for a full list of default settings.
* If some other rmw_qos_profile_t is passed to initial_profile, then the defaults will derive from
* that profile instead.
*
* \param[in] qos_initialization Specifies history policy and history depth.
* \param[in] initial_profile The rmw_qos_profile_t instance on which to base the default settings.
*/
/// Constructor which allows you to construct a QoS by giving the only required settings.
explicit
QoS(
const QoSInitialization & qos_initialization,
@@ -131,11 +69,7 @@ public:
/// Conversion constructor to ease construction in the common case of just specifying depth.
/**
* This is a convenience constructor that calls QoS(KeepLast(history_depth)).
*
* \param[in] history_depth How many messages can be queued when publishing
* with a Publisher, or how many messages can be queued before being replaced
* by a Subscription.
* Convenience constructor, equivalent to QoS(KeepLast(history_depth)).
*/
// cppcheck-suppress noExplicitConstructor
QoS(size_t history_depth); // NOLINT(runtime/explicit): conversion constructor
@@ -148,10 +82,6 @@ public:
const rmw_qos_profile_t &
get_rmw_qos_profile() const;
/// Set the history policy.
QoS &
history(HistoryPolicy history);
/// Set the history policy.
QoS &
history(rmw_qos_history_policy_t history);
@@ -168,10 +98,6 @@ public:
QoS &
reliability(rmw_qos_reliability_policy_t reliability);
/// Set the reliability setting.
QoS &
reliability(ReliabilityPolicy reliability);
/// Set the reliability setting to reliable.
QoS &
reliable();
@@ -184,10 +110,6 @@ public:
QoS &
durability(rmw_qos_durability_policy_t durability);
/// Set the durability setting.
QoS &
durability(DurabilityPolicy durability);
/// Set the durability setting to volatile.
/**
* Note that this cannot be named `volatile` because it is a C++ keyword.
@@ -219,10 +141,6 @@ public:
QoS &
liveliness(rmw_qos_liveliness_policy_t liveliness);
/// Set the liveliness setting.
QoS &
liveliness(LivelinessPolicy liveliness);
/// Set the liveliness_lease_duration setting.
QoS &
liveliness_lease_duration(rmw_time_t liveliness_lease_duration);
@@ -235,42 +153,6 @@ public:
QoS &
avoid_ros_namespace_conventions(bool avoid_ros_namespace_conventions);
/// Get the history qos policy.
HistoryPolicy
history() const;
/// Get the history depth.
size_t
depth() const;
/// Get the reliability policy.
ReliabilityPolicy
reliability() const;
/// Get the durability policy.
DurabilityPolicy
durability() const;
/// Get the deadline duration setting.
rclcpp::Duration
deadline() const;
/// Get the lifespan duration setting.
rclcpp::Duration
lifespan() const;
/// Get the liveliness policy.
LivelinessPolicy
liveliness() const;
/// Get the liveliness lease duration setting.
rclcpp::Duration
liveliness_lease_duration() const;
/// Get the `avoid ros namespace convention` setting.
bool
avoid_ros_namespace_conventions() const;
private:
rmw_qos_profile_t rmw_qos_profile_;
};
@@ -281,61 +163,6 @@ bool operator==(const QoS & left, const QoS & right);
RCLCPP_PUBLIC
bool operator!=(const QoS & left, const QoS & right);
/// Result type for checking QoS compatibility
/**
* \see rclcpp::qos_check_compatible()
*/
struct QoSCheckCompatibleResult
{
/// Compatibility result.
QoSCompatibility compatibility;
/// Reason for a (possible) incompatibility.
/**
* Set if compatiblity is QoSCompatibility::Warning or QoSCompatiblity::Error.
* Not set if the QoS profiles are compatible.
*/
std::string reason;
};
/// Check if two QoS profiles are compatible.
/**
* Two QoS profiles are compatible if a publisher and subcription
* using the QoS policies can communicate with each other.
*
* If any policies have value "system default" or "unknown" then it is possible that
* compatiblity cannot be determined.
* In this case, the value QoSCompatility::Warning is set as part of
* the returned structure.
*
* Example usage:
*
* ```cpp
* rclcpp::QoSCheckCompatibleResult result = rclcpp::qos_check_compatible(
* publisher_qos, subscription_qos);
* if (rclcpp::QoSCompatibility::Error != result.compatibility) {
* // QoS not compatible ...
* // result.reason contains info about the incompatibility
* } else if (rclcpp::QoSCompatibility::Warning != result.compatibility) {
* // QoS may not be compatible ...
* // result.reason contains info about the possible incompatibility
* }
* ```
*
* \param[in] publisher_qos: The QoS profile for a publisher.
* \param[in] subscription_qos: The QoS profile for a subscription.
* \return Struct with compatiblity set to QoSCompatibility::Ok if the QoS profiles are
* compatible, or
* \return Struct with compatibility set to QoSCompatibility::Warning if there is a chance
* the QoS profiles are not compatible, or
* \return Struct with compatibility set to QoSCompatibility::Error if the QoS profiles are
* not compatible.
* \throws rclcpp::exceptions::QoSCheckCompatibilityException if an unexpected error occurs.
*/
RCLCPP_PUBLIC
QoSCheckCompatibleResult
qos_check_compatible(const QoS & publisher_qos, const QoS & subscription_qos);
/**
* Clock QoS class
* - History: Keep last,

View File

@@ -117,15 +117,6 @@
* - Allocator related items:
* - rclcpp/allocator/allocator_common.hpp
* - rclcpp/allocator/allocator_deleter.hpp
* - Generic publisher
* - rclcpp::Node::create_generic_publisher()
* - rclcpp::GenericPublisher
* - rclcpp::GenericPublisher::publish()
* - rclcpp/generic_publisher.hpp
* - Generic subscription
* - rclcpp::Node::create_generic_subscription()
* - rclcpp::GenericSubscription
* - rclcpp/generic_subscription.hpp
* - Memory management tools:
* - rclcpp/memory_strategies.hpp
* - rclcpp/memory_strategy.hpp
@@ -143,7 +134,6 @@
* - rclcpp/scope_exit.hpp
* - rclcpp/time.hpp
* - rclcpp/utilities.hpp
* - rclcpp/typesupport_helpers.hpp
* - rclcpp/visibility_control.hpp
*/
@@ -157,15 +147,15 @@
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/parameter_client.hpp"
#include "rclcpp/parameter_event_handler.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/parameter_client.hpp"
#include "rclcpp/parameter_service.hpp"
#include "rclcpp/parameter_events_subscriber.hpp"
#include "rclcpp/rate.hpp"
#include "rclcpp/time.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/waitable.hpp"
#include "rclcpp/wait_set.hpp"
#include "rclcpp/waitable.hpp"
#endif // RCLCPP__RCLCPP_HPP_

View File

@@ -177,16 +177,25 @@ public:
using rosidl_typesupport_cpp::get_service_type_support_handle;
auto service_type_support_handle = get_service_type_support_handle<ServiceT>();
std::weak_ptr<rcl_node_t> weak_node_handle(node_handle_);
// rcl does the static memory allocation here
service_handle_ = std::shared_ptr<rcl_service_t>(
new rcl_service_t, [handle = node_handle_, service_name](rcl_service_t * service)
new rcl_service_t, [weak_node_handle](rcl_service_t * service)
{
if (rcl_service_fini(service, handle.get()) != RCL_RET_OK) {
auto handle = weak_node_handle.lock();
if (handle) {
if (rcl_service_fini(service, handle.get()) != RCL_RET_OK) {
RCLCPP_ERROR(
rclcpp::get_node_logger(handle.get()).get_child("rclcpp"),
"Error in destruction of rcl service handle: %s",
rcl_get_error_string().str);
rcl_reset_error();
}
} else {
RCLCPP_ERROR(
rclcpp::get_node_logger(handle.get()).get_child("rclcpp"),
"Error in destruction of rcl service handle: %s",
rcl_get_error_string().str);
rcl_reset_error();
rclcpp::get_logger("rclcpp"),
"Error in destruction of rcl service handle: "
"the Node Handle was destructed too early. You will leak memory");
}
delete service;
});
@@ -340,6 +349,15 @@ public:
send_response(*request_header, *response);
}
[[deprecated("use the send_response() which takes references instead of shared pointers")]]
void
send_response(
std::shared_ptr<rmw_request_id_t> req_id,
std::shared_ptr<typename ServiceT::Response> response)
{
send_response(*req_id, *response);
}
void
send_response(rmw_request_id_t & req_id, typename ServiceT::Response & response)
{

View File

@@ -171,7 +171,11 @@ public:
// First create a SubscriptionIntraProcess which will be given to the intra-process manager.
auto context = node_base->get_context();
subscription_intra_process_ = std::make_shared<SubscriptionIntraProcessT>(
using SubscriptionIntraProcessT = rclcpp::experimental::SubscriptionIntraProcess<
CallbackMessageT,
AllocatorT,
typename MessageUniquePtr::deleter_type>;
auto subscription_intra_process = std::make_shared<SubscriptionIntraProcessT>(
callback,
options.get_allocator(),
context,
@@ -181,12 +185,12 @@ public:
TRACEPOINT(
rclcpp_subscription_init,
static_cast<const void *>(get_subscription_handle().get()),
static_cast<const void *>(subscription_intra_process_.get()));
static_cast<const void *>(subscription_intra_process.get()));
// Add it to the intra process manager.
using rclcpp::experimental::IntraProcessManager;
auto ipm = context->get_sub_context<IntraProcessManager>();
uint64_t intra_process_subscription_id = ipm->add_subscription(subscription_intra_process_);
uint64_t intra_process_subscription_id = ipm->add_subscription(subscription_intra_process);
this->setup_intra_process(intra_process_subscription_id, ipm);
}
@@ -273,18 +277,11 @@ public:
return;
}
auto typed_message = std::static_pointer_cast<CallbackMessageT>(message);
std::chrono::time_point<std::chrono::system_clock> now;
if (subscription_topic_statistics_) {
// get current time before executing callback to
// exclude callback duration from topic statistics result.
now = std::chrono::system_clock::now();
}
any_callback_.dispatch(typed_message, message_info);
if (subscription_topic_statistics_) {
const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(
std::chrono::system_clock::now());
const auto time = rclcpp::Time(nanos.time_since_epoch().count());
subscription_topic_statistics_->handle_message(*typed_message, time);
}
@@ -343,11 +340,6 @@ private:
message_memory_strategy_;
/// Component which computes and publishes topic statistics for this subscriber
SubscriptionTopicStatisticsSharedPtr subscription_topic_statistics_{nullptr};
using SubscriptionIntraProcessT = rclcpp::experimental::SubscriptionIntraProcess<
CallbackMessageT,
AllocatorT,
typename MessageUniquePtr::deleter_type>;
std::shared_ptr<SubscriptionIntraProcessT> subscription_intra_process_;
};
} // namespace rclcpp

View File

@@ -31,7 +31,6 @@
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/message_info.hpp"
#include "rclcpp/network_flow_endpoint.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/serialized_message.hpp"
@@ -62,11 +61,8 @@ class SubscriptionBase : public std::enable_shared_from_this<SubscriptionBase>
public:
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(SubscriptionBase)
/// Constructor.
/// Default constructor.
/**
* This accepts rcl_subscription_options_t instead of rclcpp::SubscriptionOptions because
* rclcpp::SubscriptionOptions::to_rcl_subscription_options depends on the message type.
*
* \param[in] node_base NodeBaseInterface pointer used in parts of the setup.
* \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.
@@ -81,7 +77,7 @@ public:
const rcl_subscription_options_t & subscription_options,
bool is_serialized = false);
/// Destructor.
/// Default destructor.
RCLCPP_PUBLIC
virtual ~SubscriptionBase();
@@ -267,15 +263,6 @@ public:
bool
exchange_in_use_by_wait_set_state(void * pointer_to_subscription_part, bool in_use_state);
/// Get network flow endpoints
/**
* Describes network flow endpoints that this subscription is receiving messages on
* \return vector of NetworkFlowEndpoint
*/
RCLCPP_PUBLIC
std::vector<rclcpp::NetworkFlowEndpoint>
get_network_flow_endpoints() const;
protected:
template<typename EventCallbackT>
void

View File

@@ -93,7 +93,7 @@ create_subscription_factory(
auto allocator = options.get_allocator();
using rclcpp::AnySubscriptionCallback;
AnySubscriptionCallback<CallbackMessageT, AllocatorT> any_subscription_callback(*allocator);
AnySubscriptionCallback<CallbackMessageT, AllocatorT> any_subscription_callback(allocator);
any_subscription_callback.set(std::forward<CallbackT>(callback));
SubscriptionFactory factory {

View File

@@ -45,11 +45,6 @@ struct SubscriptionOptionsBase
/// True to ignore local publications.
bool ignore_local_publications = false;
/// Require middleware to generate unique network flow endpoints
/// Disabled by default
rmw_unique_network_flow_endpoints_requirement_t require_unique_network_flow_endpoints =
RMW_UNIQUE_NETWORK_FLOW_ENDPOINTS_NOT_REQUIRED;
/// The callback group for this subscription. NULL to use the default callback group.
rclcpp::CallbackGroup::SharedPtr callback_group = nullptr;
@@ -109,12 +104,10 @@ struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
rcl_subscription_options_t result = rcl_subscription_get_default_options();
using AllocatorTraits = std::allocator_traits<Allocator>;
using MessageAllocatorT = typename AllocatorTraits::template rebind_alloc<MessageT>;
auto message_alloc = std::make_shared<MessageAllocatorT>(*this->get_allocator().get());
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();
result.rmw_subscription_options.ignore_local_publications = this->ignore_local_publications;
result.rmw_subscription_options.require_unique_network_flow_endpoints =
this->require_unique_network_flow_endpoints;
// Apply payload to rcl_subscription_options if necessary.
if (rmw_implementation_payload && rmw_implementation_payload->has_been_customized()) {

View File

@@ -64,7 +64,7 @@ struct is_serialized_callback
template<typename MessageT>
struct extract_message_type
{
using type = typename std::remove_cv_t<std::remove_reference_t<MessageT>>;
using type = typename std::remove_cv<MessageT>::type;
};
template<typename MessageT>

View File

@@ -25,7 +25,6 @@
#include "rcl_interfaces/msg/parameter_event.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/executors.hpp"
#include "rclcpp/node_interfaces/node_parameters_interface.hpp"
@@ -33,20 +32,6 @@ namespace rclcpp
{
class Clock;
/**
* Time source that will drive the attached clocks.
*
* If the attached node `use_sim_time` parameter is `true`, the attached clocks will
* be updated based on messages received.
*
* The subscription to the clock topic created by the time source can have it's qos reconfigured
* using parameter overrides, particularly the following ones are accepted:
*
* - qos_overrides./clock.depth
* - qos_overrides./clock.durability
* - qos_overrides./clock.history
* - qos_overrides./clock.reliability
*/
class TimeSource
{
public:
@@ -58,10 +43,7 @@ public:
* \param qos QoS that will be used when creating a `/clock` subscription.
*/
RCLCPP_PUBLIC
explicit TimeSource(
rclcpp::Node::SharedPtr node,
const rclcpp::QoS & qos = rclcpp::ClockQoS(),
bool use_clock_thread = true);
explicit TimeSource(rclcpp::Node::SharedPtr node, const rclcpp::QoS & qos = rclcpp::ClockQoS());
/// Empty constructor
/**
@@ -70,9 +52,7 @@ public:
* \param qos QoS that will be used when creating a `/clock` subscription.
*/
RCLCPP_PUBLIC
explicit TimeSource(
const rclcpp::QoS & qos = rclcpp::ClockQoS(),
bool use_clock_thread = true);
explicit TimeSource(const rclcpp::QoS & qos = rclcpp::ClockQoS());
/// Attack node to the time source.
/**
@@ -124,11 +104,6 @@ public:
RCLCPP_PUBLIC
~TimeSource();
protected:
// Dedicated thread for clock subscription.
bool use_clock_thread_;
std::thread clock_executor_thread_;
private:
// Preserve the node reference
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_;
@@ -151,12 +126,9 @@ private:
using SubscriptionT = rclcpp::Subscription<MessageT, Alloc>;
std::shared_ptr<SubscriptionT> clock_subscription_{nullptr};
std::mutex clock_sub_lock_;
rclcpp::CallbackGroup::SharedPtr clock_callback_group_;
rclcpp::executors::SingleThreadedExecutor::SharedPtr clock_executor_;
std::promise<void> cancel_clock_executor_promise_;
// The clock callback itself
void clock_cb(std::shared_ptr<const rosgraph_msgs::msg::Clock> msg);
void clock_cb(const rosgraph_msgs::msg::Clock::SharedPtr msg);
// Create the subscription for the clock topic
void create_clock_sub();
@@ -170,7 +142,7 @@ private:
std::shared_ptr<ParamSubscriptionT> parameter_subscription_;
// Callback for parameter updates
void on_parameter_event(std::shared_ptr<const rcl_interfaces::msg::ParameterEvent> event);
void on_parameter_event(const rcl_interfaces::msg::ParameterEvent::SharedPtr event);
// An enum to hold the parameter state
enum UseSimTimeParameterState {UNSET, SET_TRUE, SET_FALSE};
@@ -191,7 +163,7 @@ private:
// This is needed when new clocks are added.
bool ros_time_active_{false};
// Last set message to be passed to newly registered clocks
std::shared_ptr<const rosgraph_msgs::msg::Clock> last_msg_set_;
rosgraph_msgs::msg::Clock::SharedPtr last_msg_set_;
// A lock to protect iterating the associated_clocks_ field.
std::mutex clock_list_lock_;

View File

@@ -181,7 +181,7 @@ public:
TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(&callback_),
tracetools::get_symbol(callback_));
get_symbol(callback_));
}
/// Default destructor.

View File

@@ -127,7 +127,7 @@ public:
/**
* This method acquires a lock to prevent race conditions to collectors list.
*/
virtual void publish_message_and_reset_measurements()
virtual void publish_message()
{
std::vector<MetricsMessage> msgs;
rclcpp::Time window_end{get_current_nanoseconds_since_epoch()};
@@ -136,7 +136,6 @@ public:
std::lock_guard<std::mutex> lock(mutex_);
for (auto & collector : subscriber_statistics_collectors_) {
const auto collected_stats = collector->GetStatisticsResults();
collector->ClearCurrentMeasurements();
auto message = libstatistics_collector::collector::GenerateStatisticMessage(
node_name_,

View File

@@ -1,57 +0,0 @@
// Copyright 2018, Bosch Software Innovations GmbH.
// Copyright 2021, Apex.AI 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__TYPESUPPORT_HELPERS_HPP_
#define RCLCPP__TYPESUPPORT_HELPERS_HPP_
#include <memory>
#include <string>
#include <tuple>
#include "rcpputils/shared_library.hpp"
#include "rosidl_runtime_cpp/message_type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
/// Load the type support library for the given type.
/**
* \param[in] type The topic type, e.g. "std_msgs/msg/String"
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
* \return A shared library
*/
RCLCPP_PUBLIC
std::shared_ptr<rcpputils::SharedLibrary>
get_typesupport_library(const std::string & type, const std::string & typesupport_identifier);
/// Extract the type support handle from the library.
/**
* The library needs to match the topic type. The shared library must stay loaded for the lifetime of the result.
* \param[in] type The topic type, e.g. "std_msgs/msg/String"
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
* \param[in] library The shared type support library
* \return A type support handle
*/
RCLCPP_PUBLIC
const rosidl_message_type_support_t *
get_typesupport_handle(
const std::string & type,
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library);
} // namespace rclcpp
#endif // RCLCPP__TYPESUPPORT_HELPERS_HPP_

View File

@@ -143,6 +143,21 @@ RCLCPP_PUBLIC
bool
ok(rclcpp::Context::SharedPtr context = nullptr);
/// Return true if init() has already been called for the given context.
/**
* If nullptr is given for the context, then the global context is used, i.e.
* the context initialized by rclcpp::init().
*
* Deprecated, as it is no longer different from rcl_ok().
*
* \param[in] context Optional check for initialization of this Context.
* \return true if the context is initialized, and false otherwise
*/
[[deprecated("use the function ok() instead, which has the same usage.")]]
RCLCPP_PUBLIC
bool
is_initialized(rclcpp::Context::SharedPtr context = nullptr);
/// Shutdown rclcpp context, invalidating it for derived entities.
/**
* If nullptr is given for the context, then the global context is used, i.e.

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp</name>
<version>9.1.0</version>
<version>6.0.0</version>
<description>The ROS client library in C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
<maintainer email="mabel@openrobotics.org">Mabel Zhang</maintainer>
@@ -12,14 +12,12 @@
<buildtool_depend>ament_cmake_ros</buildtool_depend>
<build_depend>ament_index_cpp</build_depend>
<build_depend>builtin_interfaces</build_depend>
<build_depend>rcl_interfaces</build_depend>
<build_depend>rosgraph_msgs</build_depend>
<build_depend>rosidl_runtime_cpp</build_depend>
<build_depend>rosidl_typesupport_c</build_depend>
<build_depend>rosidl_typesupport_cpp</build_depend>
<build_export_depend>ament_index_cpp</build_export_depend>
<build_export_depend>builtin_interfaces</build_export_depend>
<build_export_depend>rcl_interfaces</build_export_depend>
<build_export_depend>rosgraph_msgs</build_export_depend>

View File

@@ -151,9 +151,10 @@ def get_rclcpp_suffix_from_features(features):
@[ end if]@
logger.get_name(), \
@[ if 'stream' not in feature_combination]@
__VA_ARGS__); \
rclcpp::get_c_string(RCLCPP_FIRST_ARG(__VA_ARGS__, "")), \
RCLCPP_ALL_BUT_FIRST_ARGS(__VA_ARGS__,"")); \
@[ else]@
"%s", ss.str().c_str()); \
"%s", rclcpp::get_c_string(ss.str())); \
@[ end if]@
} while (0)

View File

@@ -113,7 +113,7 @@ Clock::get_clock_mutex() noexcept
void
Clock::on_time_jump(
const rcl_time_jump_t * time_jump,
const struct rcl_time_jump_t * time_jump,
bool before_jump,
void * user_data)
{

View File

@@ -291,7 +291,7 @@ Context::get_domain_id() const
}
std::string
Context::shutdown_reason() const
Context::shutdown_reason()
{
std::lock_guard<std::recursive_mutex> lock(init_mutex_);
return shutdown_reason_;
@@ -315,13 +315,9 @@ Context::shutdown(const std::string & reason)
// set shutdown reason
shutdown_reason_ = reason;
// call each shutdown callback
{
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
for (const auto & callback : on_shutdown_callbacks_) {
(*callback)();
}
for (const auto & callback : on_shutdown_callbacks_) {
callback();
}
// interrupt all blocking sleep_for() and all blocking executors or wait sets
this->interrupt_all_sleep_for();
// remove self from the global contexts
@@ -348,48 +344,20 @@ Context::shutdown(const std::string & reason)
rclcpp::Context::OnShutdownCallback
Context::on_shutdown(OnShutdownCallback callback)
{
add_on_shutdown_callback(callback);
on_shutdown_callbacks_.push_back(callback);
return callback;
}
rclcpp::OnShutdownCallbackHandle
Context::add_on_shutdown_callback(OnShutdownCallback callback)
{
auto callback_shared_ptr = std::make_shared<OnShutdownCallback>(callback);
{
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
on_shutdown_callbacks_.emplace(callback_shared_ptr);
}
OnShutdownCallbackHandle callback_handle;
callback_handle.callback = callback_shared_ptr;
return callback_handle;
}
bool
Context::remove_on_shutdown_callback(const OnShutdownCallbackHandle & callback_handle)
{
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
auto callback_shared_ptr = callback_handle.callback.lock();
if (callback_shared_ptr == nullptr) {
return false;
}
return on_shutdown_callbacks_.erase(callback_shared_ptr) == 1;
}
std::vector<rclcpp::Context::OnShutdownCallback>
const std::vector<rclcpp::Context::OnShutdownCallback> &
Context::get_on_shutdown_callbacks() const
{
std::vector<OnShutdownCallback> callbacks;
return on_shutdown_callbacks_;
}
{
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
for (auto & iter : on_shutdown_callbacks_) {
callbacks.emplace_back(*iter);
}
}
return callbacks;
std::vector<rclcpp::Context::OnShutdownCallback> &
Context::get_on_shutdown_callbacks()
{
return on_shutdown_callbacks_;
}
std::shared_ptr<rcl_context_t>

View File

@@ -1,104 +0,0 @@
// Copyright 2021 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/detail/mutex_two_priorities.hpp"
#include <mutex>
namespace rclcpp
{
namespace detail
{
using LowPriorityLockable = MutexTwoPriorities::LowPriorityLockable;
using HighPriorityLockable = MutexTwoPriorities::HighPriorityLockable;
HighPriorityLockable::HighPriorityLockable(MutexTwoPriorities & parent)
: parent_(parent)
{}
void
HighPriorityLockable::lock()
{
std::unique_lock<std::mutex> guard{parent_.cv_mutex_};
if (parent_.data_taken_) {
++parent_.hp_waiting_count_;
while (parent_.data_taken_) {
parent_.hp_cv_.wait(guard);
}
--parent_.hp_waiting_count_;
}
parent_.data_taken_ = true;
}
void
HighPriorityLockable::unlock()
{
bool notify_lp{false};
{
std::lock_guard<std::mutex> guard{parent_.cv_mutex_};
parent_.data_taken_ = false;
notify_lp = 0u == parent_.hp_waiting_count_;
}
if (notify_lp) {
parent_.lp_cv_.notify_one();
} else {
parent_.hp_cv_.notify_one();
}
}
LowPriorityLockable::LowPriorityLockable(MutexTwoPriorities & parent)
: parent_(parent)
{}
void
LowPriorityLockable::lock()
{
std::unique_lock<std::mutex> guard{parent_.cv_mutex_};
while (parent_.data_taken_ || parent_.hp_waiting_count_) {
parent_.lp_cv_.wait(guard);
}
parent_.data_taken_ = true;
}
void
LowPriorityLockable::unlock()
{
bool notify_lp{false};
{
std::lock_guard<std::mutex> guard{parent_.cv_mutex_};
parent_.data_taken_ = false;
notify_lp = 0u == parent_.hp_waiting_count_;
}
if (notify_lp) {
parent_.lp_cv_.notify_one();
} else {
parent_.hp_cv_.notify_one();
}
}
HighPriorityLockable
MutexTwoPriorities::get_high_priority_lockable()
{
return HighPriorityLockable{*this};
}
LowPriorityLockable
MutexTwoPriorities::get_low_priority_lockable()
{
return LowPriorityLockable{*this};
}
} // namespace detail
} // namespace rclcpp

View File

@@ -1,77 +0,0 @@
// Copyright 2021 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 "./resolve_parameter_overrides.hpp"
#include <string>
#include <map>
#include <vector>
#include "rcl_yaml_param_parser/parser.h"
#include "rclcpp/scope_exit.hpp"
#include "rclcpp/parameter_map.hpp"
std::map<std::string, rclcpp::ParameterValue>
rclcpp::detail::resolve_parameter_overrides(
const std::string & node_fqn,
const std::vector<rclcpp::Parameter> & parameter_overrides,
const rcl_arguments_t * local_args,
const rcl_arguments_t * global_args)
{
std::map<std::string, rclcpp::ParameterValue> result;
// global before local so that local overwrites global
std::array<const rcl_arguments_t *, 2> argument_sources = {global_args, local_args};
// Get fully qualified node name post-remapping to use to find node's params in yaml files
for (const rcl_arguments_t * source : argument_sources) {
if (!source) {
continue;
}
rcl_params_t * params = NULL;
rcl_ret_t ret = rcl_arguments_get_param_overrides(source, &params);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
if (params) {
auto cleanup_params = make_scope_exit(
[params]() {
rcl_yaml_node_struct_fini(params);
});
rclcpp::ParameterMap initial_map = rclcpp::parameter_map_from(params);
// Enforce wildcard matching precedence
// TODO(cottsay) implement further wildcard matching
const std::array<std::string, 2> node_matching_names{"/**", node_fqn};
for (const auto & node_name : node_matching_names) {
if (initial_map.count(node_name) > 0) {
// Combine parameter yaml files, overwriting values in older ones
for (const rclcpp::Parameter & param : initial_map.at(node_name)) {
result[param.get_name()] =
rclcpp::ParameterValue(param.get_value_message());
}
}
}
}
}
// parameter overrides passed to constructor will overwrite overrides from yaml file sources
for (auto & param : parameter_overrides) {
result[param.get_name()] =
rclcpp::ParameterValue(param.get_value_message());
}
return result;
}

View File

@@ -1,44 +0,0 @@
// Copyright 2021 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DETAIL__RESOLVE_PARAMETER_OVERRIDES_HPP_
#define RCLCPP__DETAIL__RESOLVE_PARAMETER_OVERRIDES_HPP_
#include <string>
#include <map>
#include <vector>
#include "rcl/arguments.h"
#include "rclcpp/parameter.hpp"
#include "rclcpp/parameter_value.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace detail
{
/// \internal Get the parameter overrides from the arguments.
RCLCPP_LOCAL
std::map<std::string, rclcpp::ParameterValue>
resolve_parameter_overrides(
const std::string & node_name,
const std::vector<rclcpp::Parameter> & parameter_overrides,
const rcl_arguments_t * local_args,
const rcl_arguments_t * global_args);
} // namespace detail
} // namespace rclcpp
#endif // RCLCPP__DETAIL__RESOLVE_PARAMETER_OVERRIDES_HPP_

View File

@@ -67,27 +67,13 @@ Duration::operator builtin_interfaces::msg::Duration() const
{
builtin_interfaces::msg::Duration msg_duration;
constexpr rcl_duration_value_t kDivisor = RCL_S_TO_NS(1);
constexpr int32_t max_s = std::numeric_limits<int32_t>::max();
constexpr int32_t min_s = std::numeric_limits<int32_t>::min();
constexpr uint32_t max_ns = std::numeric_limits<uint32_t>::max();
const auto result = std::div(rcl_duration_.nanoseconds, kDivisor);
if (result.rem >= 0) {
// saturate if we will overflow
if (result.quot > max_s) {
msg_duration.sec = max_s;
msg_duration.nanosec = max_ns;
} else {
msg_duration.sec = static_cast<int32_t>(result.quot);
msg_duration.nanosec = static_cast<uint32_t>(result.rem);
}
msg_duration.sec = static_cast<std::int32_t>(result.quot);
msg_duration.nanosec = static_cast<std::uint32_t>(result.rem);
} else {
if (result.quot <= min_s) {
msg_duration.sec = min_s;
msg_duration.nanosec = 0u;
} else {
msg_duration.sec = static_cast<int32_t>(result.quot - 1);
msg_duration.nanosec = static_cast<uint32_t>(kDivisor + result.rem);
}
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;
}
@@ -252,38 +238,14 @@ Duration::to_rmw_time() const
throw std::runtime_error("rmw_time_t cannot be negative");
}
// Purposefully avoid creating from builtin_interfaces::msg::Duration
// to avoid possible overflow converting from int64_t to int32_t, then back to uint64_t
// reuse conversion logic from msg creation
builtin_interfaces::msg::Duration msg = *this;
rmw_time_t result;
constexpr rcl_duration_value_t kDivisor = RCL_S_TO_NS(1);
const auto div_result = std::div(rcl_duration_.nanoseconds, kDivisor);
result.sec = static_cast<uint64_t>(div_result.quot);
result.nsec = static_cast<uint64_t>(div_result.rem);
result.sec = static_cast<uint64_t>(msg.sec);
result.nsec = static_cast<uint64_t>(msg.nanosec);
return result;
}
Duration
Duration::from_rmw_time(rmw_time_t duration)
{
Duration ret;
constexpr rcl_duration_value_t limit_ns = std::numeric_limits<rcl_duration_value_t>::max();
constexpr rcl_duration_value_t limit_sec = RCL_NS_TO_S(limit_ns);
if (duration.sec > limit_sec || duration.nsec > limit_ns) {
// saturate if will overflow
ret.rcl_duration_.nanoseconds = limit_ns;
return ret;
}
uint64_t total_ns = RCL_S_TO_NS(duration.sec) + duration.nsec;
if (total_ns > limit_ns) {
// saturate if will overflow
ret.rcl_duration_.nanoseconds = limit_ns;
return ret;
}
ret.rcl_duration_.nanoseconds = static_cast<rcl_duration_value_t>(total_ns);
return ret;
}
Duration
Duration::from_seconds(double seconds)
{

View File

@@ -56,7 +56,7 @@ Executor::Executor(const rclcpp::ExecutorOptions & options)
throw_from_rcl_error(ret, "Failed to create interrupt guard condition in Executor constructor");
}
shutdown_callback_handle_ = context_->add_on_shutdown_callback(
context_->on_shutdown(
[weak_gc = std::weak_ptr<rclcpp::GuardCondition>{shutdown_guard_condition_}]() {
auto strong_gc = weak_gc.lock();
if (strong_gc) {
@@ -138,21 +138,12 @@ Executor::~Executor()
}
// Remove and release the sigint guard condition
memory_strategy_->remove_guard_condition(&shutdown_guard_condition_->get_rcl_guard_condition());
// Remove shutdown callback handle registered to Context
if (!context_->remove_on_shutdown_callback(shutdown_callback_handle_)) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"failed to remove registered on_shutdown callback");
rcl_reset_error();
}
}
std::vector<rclcpp::CallbackGroup::WeakPtr>
Executor::get_all_callback_groups()
{
std::vector<rclcpp::CallbackGroup::WeakPtr> groups;
std::lock_guard<std::mutex> guard{mutex_};
for (const auto & group_node_ptr : weak_groups_associated_with_executor_to_nodes_) {
groups.push_back(group_node_ptr.first);
}
@@ -166,7 +157,6 @@ std::vector<rclcpp::CallbackGroup::WeakPtr>
Executor::get_manually_added_callback_groups()
{
std::vector<rclcpp::CallbackGroup::WeakPtr> groups;
std::lock_guard<std::mutex> guard{mutex_};
for (auto const & group_node_ptr : weak_groups_associated_with_executor_to_nodes_) {
groups.push_back(group_node_ptr.first);
}
@@ -177,7 +167,6 @@ std::vector<rclcpp::CallbackGroup::WeakPtr>
Executor::get_automatically_added_callback_groups_from_nodes()
{
std::vector<rclcpp::CallbackGroup::WeakPtr> groups;
std::lock_guard<std::mutex> guard{mutex_};
for (auto const & group_node_ptr : weak_groups_to_nodes_associated_with_executor_) {
groups.push_back(group_node_ptr.first);
}
@@ -244,6 +233,7 @@ Executor::add_callback_group_to_map(
}
}
// 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());
}
}
@@ -254,7 +244,6 @@ Executor::add_callback_group(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
bool notify)
{
std::lock_guard<std::mutex> guard{mutex_};
this->add_callback_group_to_map(
group_ptr,
node_ptr,
@@ -270,7 +259,6 @@ Executor::add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_pt
if (has_executor.exchange(true)) {
throw std::runtime_error("Node has already been added to an executor.");
}
std::lock_guard<std::mutex> guard{mutex_};
for (auto & weak_group : node_ptr->get_callback_groups()) {
auto group_ptr = weak_group.lock();
if (group_ptr != nullptr && !group_ptr->get_associated_with_executor_atomic().load() &&
@@ -319,6 +307,7 @@ Executor::remove_callback_group_from_map(
throw_from_rcl_error(ret, "Failed to trigger guard condition on callback group remove");
}
}
std::unique_lock<std::mutex> lock(memory_strategy_mutex_);
memory_strategy_->remove_guard_condition(node_ptr->get_notify_guard_condition());
}
}
@@ -328,7 +317,6 @@ Executor::remove_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr,
bool notify)
{
std::lock_guard<std::mutex> guard{mutex_};
this->remove_callback_group_from_map(
group_ptr,
weak_groups_associated_with_executor_to_nodes_,
@@ -348,7 +336,6 @@ Executor::remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node
throw std::runtime_error("Node needs to be associated with an executor.");
}
std::lock_guard<std::mutex> guard{mutex_};
bool found_node = false;
auto node_it = weak_nodes_.begin();
while (node_it != weak_nodes_.end()) {
@@ -502,7 +489,6 @@ Executor::set_memory_strategy(rclcpp::memory_strategy::MemoryStrategy::SharedPtr
if (memory_strategy == nullptr) {
throw std::runtime_error("Received NULL memory strategy in executor.");
}
std::lock_guard<std::mutex> guard{mutex_};
memory_strategy_ = memory_strategy;
}
@@ -618,18 +604,16 @@ Executor::execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
return true;
},
[&]() {subscription->handle_loaned_message(loaned_msg, message_info);});
if (nullptr != loaned_msg) {
rcl_ret_t ret = rcl_return_loaned_message_from_subscription(
subscription->get_subscription_handle().get(),
loaned_msg);
if (RCL_RET_OK != ret) {
RCLCPP_ERROR(
rclcpp::get_logger("rclcpp"),
"rcl_return_loaned_message_from_subscription() failed for subscription on topic '%s': %s",
subscription->get_topic_name(), rcl_get_error_string().str);
}
loaned_msg = nullptr;
rcl_ret_t ret = rcl_return_loaned_message_from_subscription(
subscription->get_subscription_handle().get(),
loaned_msg);
if (RCL_RET_OK != ret) {
RCLCPP_ERROR(
rclcpp::get_logger("rclcpp"),
"rcl_return_loaned_message_from_subscription() failed for subscription on topic '%s': %s",
subscription->get_topic_name(), rcl_get_error_string().str);
}
loaned_msg = nullptr;
} else {
// This case is taking a copy of the message data from the middleware via
// inter-process communication.
@@ -678,7 +662,7 @@ void
Executor::wait_for_work(std::chrono::nanoseconds timeout)
{
{
std::lock_guard<std::mutex> guard(mutex_);
std::unique_lock<std::mutex> lock(memory_strategy_mutex_);
// Check weak_nodes_ to find any callback group that is not owned
// by an executor and add it to the list of callbackgroups for
@@ -757,14 +741,12 @@ Executor::wait_for_work(std::chrono::nanoseconds timeout)
// check the null handles in the wait set and remove them from the handles in memory strategy
// for callback-based entities
std::lock_guard<std::mutex> guard(mutex_);
memory_strategy_->remove_null_handles(&wait_set_);
}
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
Executor::get_node_by_group(
const rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap &
weak_groups_to_nodes,
rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap weak_groups_to_nodes,
rclcpp::CallbackGroup::SharedPtr group)
{
if (!group) {
@@ -782,7 +764,6 @@ Executor::get_node_by_group(
rclcpp::CallbackGroup::SharedPtr
Executor::get_group_by_timer(rclcpp::TimerBase::SharedPtr timer)
{
std::lock_guard<std::mutex> guard{mutex_};
for (const auto & pair : weak_groups_associated_with_executor_to_nodes_) {
auto group = pair.first.lock();
if (!group) {
@@ -823,11 +804,9 @@ Executor::get_next_ready_executable(AnyExecutable & any_executable)
bool
Executor::get_next_ready_executable_from_map(
AnyExecutable & any_executable,
const rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap &
weak_groups_to_nodes)
rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap weak_groups_to_nodes)
{
bool success = false;
std::lock_guard<std::mutex> guard{mutex_};
// Check the timers to see if there are any that are ready
memory_strategy_->get_next_timer(any_executable, weak_groups_to_nodes);
if (any_executable.timer) {
@@ -914,8 +893,7 @@ Executor::get_next_executable(AnyExecutable & any_executable, std::chrono::nanos
bool
Executor::has_node(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
const rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap &
weak_groups_to_nodes) const
rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap weak_groups_to_nodes) const
{
return std::find_if(
weak_groups_to_nodes.begin(),

View File

@@ -22,7 +22,6 @@
#include "rclcpp/utilities.hpp"
#include "rclcpp/scope_exit.hpp"
using rclcpp::detail::MutexTwoPriorities;
using rclcpp::executors::MultiThreadedExecutor;
MultiThreadedExecutor::MultiThreadedExecutor(
@@ -52,8 +51,7 @@ MultiThreadedExecutor::spin()
std::vector<std::thread> threads;
size_t thread_id = 0;
{
auto low_priority_wait_mutex = wait_mutex_.get_low_priority_lockable();
std::lock_guard<MutexTwoPriorities::LowPriorityLockable> wait_lock(low_priority_wait_mutex);
std::lock_guard<std::mutex> wait_lock(wait_mutex_);
for (; thread_id < number_of_threads_ - 1; ++thread_id) {
auto func = std::bind(&MultiThreadedExecutor::run, this, thread_id);
threads.emplace_back(func);
@@ -78,8 +76,7 @@ MultiThreadedExecutor::run(size_t)
while (rclcpp::ok(this->context_) && spinning.load()) {
rclcpp::AnyExecutable any_exec;
{
auto low_priority_wait_mutex = wait_mutex_.get_low_priority_lockable();
std::lock_guard<MutexTwoPriorities::LowPriorityLockable> wait_lock(low_priority_wait_mutex);
std::lock_guard<std::mutex> wait_lock(wait_mutex_);
if (!rclcpp::ok(this->context_) || !spinning.load()) {
return;
}
@@ -106,8 +103,7 @@ MultiThreadedExecutor::run(size_t)
execute_any_executable(any_exec);
if (any_exec.timer) {
auto high_priority_wait_mutex = wait_mutex_.get_high_priority_lockable();
std::lock_guard<MutexTwoPriorities::HighPriorityLockable> wait_lock(high_priority_wait_mutex);
std::lock_guard<std::mutex> wait_lock(wait_mutex_);
auto it = scheduled_timers_.find(any_exec.timer);
if (it != scheduled_timers_.end()) {
scheduled_timers_.erase(it);

View File

@@ -76,13 +76,9 @@ StaticExecutorEntitiesCollector::init(
// Add executor's guard condition
memory_strategy_->add_guard_condition(executor_guard_condition);
// Get memory strategy and executable list. Prepare wait_set_
std::shared_ptr<void> shared_ptr;
execute(shared_ptr);
// The entities collector is now initialized
initialized_ = true;
}
void
@@ -327,7 +323,8 @@ StaticExecutorEntitiesCollector::add_callback_group(
throw std::runtime_error("Callback group was already added to executor.");
}
if (is_new_node) {
weak_nodes_to_guard_conditions_[node_ptr] = node_ptr->get_notify_guard_condition();
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr node_weak_ptr(node_ptr);
weak_nodes_to_guard_conditions_[node_weak_ptr] = node_ptr->get_notify_guard_condition();
return true;
}
return false;

View File

@@ -14,7 +14,6 @@
#include "rclcpp/executors/static_single_threaded_executor.hpp"
#include <chrono>
#include <memory>
#include <vector>
@@ -30,12 +29,7 @@ StaticSingleThreadedExecutor::StaticSingleThreadedExecutor(
entities_collector_ = std::make_shared<StaticExecutorEntitiesCollector>();
}
StaticSingleThreadedExecutor::~StaticSingleThreadedExecutor()
{
if (entities_collector_->is_init()) {
entities_collector_->fini();
}
}
StaticSingleThreadedExecutor::~StaticSingleThreadedExecutor() {}
void
StaticSingleThreadedExecutor::spin()
@@ -48,6 +42,7 @@ StaticSingleThreadedExecutor::spin()
// Set memory_strategy_ and exec_list_ based on weak_nodes_
// Prepare wait_set_ based on memory_strategy_
entities_collector_->init(&wait_set_, memory_strategy_, &interrupt_guard_condition_);
RCLCPP_SCOPE_EXIT(entities_collector_->fini());
while (rclcpp::ok(this->context_) && spinning.load()) {
// Refresh wait set and wait for work
@@ -56,79 +51,6 @@ StaticSingleThreadedExecutor::spin()
}
}
void
StaticSingleThreadedExecutor::spin_some(std::chrono::nanoseconds max_duration)
{
// In this context a 0 input max_duration means no duration limit
if (std::chrono::nanoseconds(0) == max_duration) {
max_duration = std::chrono::nanoseconds::max();
}
return this->spin_some_impl(max_duration, false);
}
void
StaticSingleThreadedExecutor::spin_all(std::chrono::nanoseconds max_duration)
{
if (max_duration <= std::chrono::nanoseconds(0)) {
throw std::invalid_argument("max_duration must be positive");
}
return this->spin_some_impl(max_duration, true);
}
void
StaticSingleThreadedExecutor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
{
// Make sure the entities collector has been initialized
if (!entities_collector_->is_init()) {
entities_collector_->init(&wait_set_, memory_strategy_, &interrupt_guard_condition_);
}
auto start = std::chrono::steady_clock::now();
auto max_duration_not_elapsed = [max_duration, start]() {
if (std::chrono::nanoseconds(0) == max_duration) {
// told to spin forever if need be
return true;
} else if (std::chrono::steady_clock::now() - start < max_duration) {
// told to spin only for some maximum amount of time
return true;
}
// spun too long
return false;
};
if (spinning.exchange(true)) {
throw std::runtime_error("spin_some() called while already spinning");
}
RCLCPP_SCOPE_EXIT(this->spinning.store(false); );
while (rclcpp::ok(context_) && spinning.load() && max_duration_not_elapsed()) {
// Get executables that are ready now
entities_collector_->refresh_wait_set(std::chrono::milliseconds::zero());
// Execute ready executables
bool work_available = execute_ready_executables();
if (!work_available || !exhaustive) {
break;
}
}
}
void
StaticSingleThreadedExecutor::spin_once_impl(std::chrono::nanoseconds timeout)
{
// Make sure the entities collector has been initialized
if (!entities_collector_->is_init()) {
entities_collector_->init(&wait_set_, memory_strategy_, &interrupt_guard_condition_);
}
if (rclcpp::ok(context_) && spinning.load()) {
// Wait until we have a ready entity or timeout expired
entities_collector_->refresh_wait_set(timeout);
// Execute ready executables
execute_ready_executables(true);
}
}
void
StaticSingleThreadedExecutor::add_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr,
@@ -216,20 +138,14 @@ StaticSingleThreadedExecutor::remove_node(std::shared_ptr<rclcpp::Node> node_ptr
this->remove_node(node_ptr->get_node_base_interface(), notify);
}
bool
StaticSingleThreadedExecutor::execute_ready_executables(bool spin_once)
void
StaticSingleThreadedExecutor::execute_ready_executables()
{
bool any_ready_executable = false;
// Execute all the ready subscriptions
for (size_t i = 0; i < wait_set_.size_of_subscriptions; ++i) {
if (i < entities_collector_->get_number_of_subscriptions()) {
if (wait_set_.subscriptions[i]) {
execute_subscription(entities_collector_->get_subscription(i));
if (spin_once) {
return true;
}
any_ready_executable = true;
}
}
}
@@ -238,10 +154,6 @@ StaticSingleThreadedExecutor::execute_ready_executables(bool spin_once)
if (i < entities_collector_->get_number_of_timers()) {
if (wait_set_.timers[i] && entities_collector_->get_timer(i)->is_ready()) {
execute_timer(entities_collector_->get_timer(i));
if (spin_once) {
return true;
}
any_ready_executable = true;
}
}
}
@@ -250,10 +162,6 @@ StaticSingleThreadedExecutor::execute_ready_executables(bool spin_once)
if (i < entities_collector_->get_number_of_services()) {
if (wait_set_.services[i]) {
execute_service(entities_collector_->get_service(i));
if (spin_once) {
return true;
}
any_ready_executable = true;
}
}
}
@@ -262,24 +170,14 @@ StaticSingleThreadedExecutor::execute_ready_executables(bool spin_once)
if (i < entities_collector_->get_number_of_clients()) {
if (wait_set_.clients[i]) {
execute_client(entities_collector_->get_client(i));
if (spin_once) {
return true;
}
any_ready_executable = true;
}
}
}
// Execute all the ready waitables
for (size_t i = 0; i < entities_collector_->get_number_of_waitables(); ++i) {
auto waitable = entities_collector_->get_waitable(i);
if (waitable->is_ready(&wait_set_)) {
auto data = waitable->take_data();
waitable->execute(data);
if (spin_once) {
return true;
}
any_ready_executable = true;
if (entities_collector_->get_waitable(i)->is_ready(&wait_set_)) {
std::shared_ptr<void> shared_ptr;
entities_collector_->get_waitable(i)->execute(shared_ptr);
}
}
return any_ready_executable;
}

View File

@@ -1,34 +0,0 @@
// Copyright 2018, Bosch Software Innovations GmbH.
// Copyright 2021, Apex.AI 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/generic_publisher.hpp"
#include <memory>
#include <string>
namespace rclcpp
{
void GenericPublisher::publish(const rclcpp::SerializedMessage & message)
{
auto return_code = rcl_publish_serialized_message(
get_publisher_handle().get(), &message.get_rcl_serialized_message(), NULL);
if (return_code != RCL_RET_OK) {
rclcpp::exceptions::throw_from_rcl_error(return_code, "failed to publish serialized message");
}
}
} // namespace rclcpp

View File

@@ -1,67 +0,0 @@
// Copyright 2018, Bosch Software Innovations GmbH.
// Copyright 2021, Apex.AI 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/generic_subscription.hpp"
#include <memory>
#include <string>
#include "rcl/subscription.h"
#include "rclcpp/exceptions.hpp"
namespace rclcpp
{
std::shared_ptr<void> GenericSubscription::create_message()
{
return create_serialized_message();
}
std::shared_ptr<rclcpp::SerializedMessage> GenericSubscription::create_serialized_message()
{
return std::make_shared<rclcpp::SerializedMessage>(0);
}
void GenericSubscription::handle_message(
std::shared_ptr<void> & message, const rclcpp::MessageInfo & message_info)
{
(void) message_info;
auto typed_message = std::static_pointer_cast<rclcpp::SerializedMessage>(message);
callback_(typed_message);
}
void GenericSubscription::handle_loaned_message(
void * message, const rclcpp::MessageInfo & message_info)
{
(void) message;
(void) message_info;
throw rclcpp::exceptions::UnimplementedError(
"handle_loaned_message is not implemented for GenericSubscription");
}
void GenericSubscription::return_message(std::shared_ptr<void> & message)
{
auto typed_message = std::static_pointer_cast<rclcpp::SerializedMessage>(message);
return_serialized_message(typed_message);
}
void GenericSubscription::return_serialized_message(
std::shared_ptr<rclcpp::SerializedMessage> & message)
{
message.reset();
}
} // namespace rclcpp

View File

@@ -157,13 +157,7 @@ IntraProcessManager::get_subscription_intra_process(uint64_t intra_process_subsc
if (subscription_it == subscriptions_.end()) {
return nullptr;
} else {
auto subscription = subscription_it->second.subscription.lock();
if (subscription) {
return subscription;
} else {
subscriptions_.erase(subscription_it);
return nullptr;
}
return subscription_it->second.subscription;
}
}

View File

@@ -14,8 +14,6 @@
#include <string>
#include "rcl_logging_interface/rcl_logging_interface.h"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/logger.hpp"
#include "rclcpp/logging.hpp"
@@ -40,28 +38,12 @@ get_node_logger(const rcl_node_t * node)
const char * logger_name = rcl_node_get_logger_name(node);
if (nullptr == logger_name) {
auto logger = rclcpp::get_logger("rclcpp");
RCLCPP_ERROR(
logger, "failed to get logger name from node at address %p",
static_cast<void *>(const_cast<rcl_node_t *>(node)));
RCLCPP_ERROR(logger, "failed to get logger name from node at address %p", node);
return logger;
}
return rclcpp::get_logger(logger_name);
}
rcpputils::fs::path
get_logging_directory()
{
char * log_dir = NULL;
auto allocator = rcutils_get_default_allocator();
rcl_logging_ret_t ret = rcl_logging_get_logging_directory(allocator, &log_dir);
if (RCL_LOGGING_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
std::string path{log_dir};
allocator.deallocate(log_dir, allocator.state);
return path;
}
void
Logger::set_level(Level level)
{

View File

@@ -1,84 +0,0 @@
// Copyright 2020 Ericsson AB
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string>
#include "rclcpp/network_flow_endpoint.hpp"
namespace rclcpp
{
const std::string &
NetworkFlowEndpoint::transport_protocol() const
{
return transport_protocol_;
}
const std::string &
NetworkFlowEndpoint::internet_protocol() const
{
return internet_protocol_;
}
uint16_t NetworkFlowEndpoint::transport_port() const
{
return transport_port_;
}
uint32_t NetworkFlowEndpoint::flow_label() const
{
return flow_label_;
}
uint8_t NetworkFlowEndpoint::dscp() const
{
return dscp_;
}
const std::string &
NetworkFlowEndpoint::internet_address() const
{
return internet_address_;
}
bool operator==(const NetworkFlowEndpoint & left, const NetworkFlowEndpoint & right)
{
return left.transport_protocol_ == right.transport_protocol_ &&
left.internet_protocol_ == right.internet_protocol_ &&
left.transport_port_ == right.transport_port_ &&
left.flow_label_ == right.flow_label_ &&
left.dscp_ == right.dscp_ &&
left.internet_address_ == right.internet_address_;
}
bool operator!=(const NetworkFlowEndpoint & left, const NetworkFlowEndpoint & right)
{
return !(left == right);
}
std::ostream & operator<<(std::ostream & os, const NetworkFlowEndpoint & network_flow_endpoint)
{
// Stream out in JSON-like format
os << "{" <<
"\"transportProtocol\": \"" << network_flow_endpoint.transport_protocol_ << "\", " <<
"\"internetProtocol\": \"" << network_flow_endpoint.internet_protocol_ << "\", " <<
"\"transportPort\": \"" << network_flow_endpoint.transport_port_ << "\", " <<
"\"flowLabel\": \"" << std::to_string(network_flow_endpoint.flow_label_) << "\", " <<
"\"dscp\": \"" << std::to_string(network_flow_endpoint.dscp_) << "\", " <<
"\"internetAddress\": \"" << network_flow_endpoint.internet_address_ << "\"" <<
"}";
return os;
}
} // namespace rclcpp

View File

@@ -13,7 +13,6 @@
// limitations under the License.
#include <algorithm>
#include <array>
#include <limits>
#include <map>
#include <memory>
@@ -21,9 +20,6 @@
#include <utility>
#include <vector>
#include "rcl/arguments.h"
#include "rclcpp/detail/qos_parameters.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/graph_listener.hpp"
#include "rclcpp/node.hpp"
@@ -37,12 +33,9 @@
#include "rclcpp/node_interfaces/node_timers.hpp"
#include "rclcpp/node_interfaces/node_topics.hpp"
#include "rclcpp/node_interfaces/node_waitables.hpp"
#include "rclcpp/qos_overriding_options.hpp"
#include "rmw/validate_namespace.h"
#include "./detail/resolve_parameter_overrides.hpp"
using rclcpp::Node;
using rclcpp::NodeOptions;
using rclcpp::exceptions::throw_from_rcl_error;
@@ -101,45 +94,6 @@ Node::Node(
{
}
static
rclcpp::QoS
get_parameter_events_qos(
rclcpp::node_interfaces::NodeBaseInterface & node_base,
const rclcpp::NodeOptions & options)
{
auto final_qos = options.parameter_event_qos();
const rcl_arguments_t * global_args = nullptr;
auto * rcl_options = options.get_rcl_node_options();
if (rcl_options->use_global_arguments) {
auto context_ptr = node_base.get_context()->get_rcl_context();
global_args = &(context_ptr->global_arguments);
}
auto parameter_overrides = rclcpp::detail::resolve_parameter_overrides(
node_base.get_fully_qualified_name(),
options.parameter_overrides(),
&rcl_options->arguments,
global_args);
auto final_topic_name = node_base.resolve_topic_or_service_name("/parameter_events", false);
auto prefix = "qos_overrides." + final_topic_name + ".";
std::array<rclcpp::QosPolicyKind, 4> policies = {
rclcpp::QosPolicyKind::Depth,
rclcpp::QosPolicyKind::Durability,
rclcpp::QosPolicyKind::History,
rclcpp::QosPolicyKind::Reliability,
};
for (const auto & policy : policies) {
auto param_name = prefix + rclcpp::qos_policy_kind_to_cstr(policy);
auto it = parameter_overrides.find(param_name);
auto value = it != parameter_overrides.end() ?
it->second :
rclcpp::detail::get_default_qos_param_value(policy, options.parameter_event_qos());
rclcpp::detail::apply_qos_override(policy, value, final_qos);
}
return final_qos;
}
Node::Node(
const std::string & node_name,
const std::string & namespace_,
@@ -172,9 +126,7 @@ Node::Node(
options.parameter_overrides(),
options.start_parameter_services(),
options.start_parameter_event_publisher(),
// This is needed in order to apply parameter overrides to the qos profile provided in
// options.
get_parameter_events_qos(*node_base_, options),
options.parameter_event_qos(),
options.parameter_event_publisher_options(),
options.allow_undeclared_parameters(),
options.automatically_declare_parameters_from_overrides()
@@ -187,28 +139,13 @@ Node::Node(
node_logging_,
node_clock_,
node_parameters_,
options.clock_qos(),
options.use_clock_thread()
options.clock_qos()
)),
node_waitables_(new rclcpp::node_interfaces::NodeWaitables(node_base_.get())),
node_options_(options),
sub_namespace_(""),
effective_namespace_(create_effective_namespace(this->get_namespace(), sub_namespace_))
{
// we have got what we wanted directly from the overrides,
// but declare the parameters anyway so they are visible.
rclcpp::detail::declare_qos_parameters(
rclcpp::QosOverridingOptions
{
QosPolicyKind::Depth,
QosPolicyKind::Durability,
QosPolicyKind::History,
QosPolicyKind::Reliability,
},
node_parameters_,
node_topics_->resolve_topic_name("/parameter_events"),
options.parameter_event_qos(),
rclcpp::detail::PublisherQosParametersTraits{});
}
Node::Node(
@@ -248,18 +185,7 @@ Node::Node(
}
Node::~Node()
{
// release sub-interfaces in an order that allows them to consult with node_base during tear-down
node_waitables_.reset();
node_time_source_.reset();
node_parameters_.reset();
node_clock_.reset();
node_services_.reset();
node_topics_.reset();
node_timers_.reset();
node_logging_.reset();
node_graph_.reset();
}
{}
const char *
Node::get_name() const
@@ -293,24 +219,6 @@ Node::create_callback_group(
return node_base_->create_callback_group(group_type, automatically_add_to_executor_with_node);
}
const rclcpp::ParameterValue &
Node::declare_parameter(const std::string & name)
{
#ifndef _WIN32
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
return this->node_parameters_->declare_parameter(name);
#ifndef _WIN32
# pragma GCC diagnostic pop
#else
# pragma warning(pop)
#endif
}
const rclcpp::ParameterValue &
Node::declare_parameter(
const std::string & name,
@@ -325,20 +233,6 @@ Node::declare_parameter(
ignore_override);
}
const rclcpp::ParameterValue &
Node::declare_parameter(
const std::string & name,
rclcpp::ParameterType type,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
bool ignore_override)
{
return this->node_parameters_->declare_parameter(
name,
type,
parameter_descriptor,
ignore_override);
}
void
Node::undeclare_parameter(const std::string & name)
{

View File

@@ -16,10 +16,8 @@
#include <rcl_yaml_param_parser/parser.h>
#include <array>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <limits>
#include <map>
@@ -36,8 +34,6 @@
#include "rcutils/logging_macros.h"
#include "rmw/qos_profiles.h"
#include "../detail/resolve_parameter_overrides.hpp"
using rclcpp::node_interfaces::NodeParameters;
NodeParameters::NodeParameters(
@@ -89,27 +85,60 @@ NodeParameters::NodeParameters(
throw std::runtime_error("Need valid node options in NodeParameters");
}
const rcl_arguments_t * global_args = nullptr;
std::vector<const rcl_arguments_t *> argument_sources;
// global before local so that local overwrites global
if (options->use_global_arguments) {
auto context_ptr = node_base->get_context()->get_rcl_context();
global_args = &(context_ptr->global_arguments);
argument_sources.push_back(&(context_ptr->global_arguments));
}
argument_sources.push_back(&options->arguments);
// Get fully qualified node name post-remapping to use to find node's params in yaml files
combined_name_ = node_base->get_fully_qualified_name();
parameter_overrides_ = rclcpp::detail::resolve_parameter_overrides(
combined_name_, parameter_overrides, &options->arguments, global_args);
for (const rcl_arguments_t * source : argument_sources) {
rcl_params_t * params = NULL;
rcl_ret_t ret = rcl_arguments_get_param_overrides(source, &params);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
if (params) {
auto cleanup_params = make_scope_exit(
[params]() {
rcl_yaml_node_struct_fini(params);
});
rclcpp::ParameterMap initial_map = rclcpp::parameter_map_from(params);
// Enforce wildcard matching precedence
// TODO(cottsay) implement further wildcard matching
const std::vector<std::string> node_matching_names{"/**", combined_name_};
for (const auto & node_name : node_matching_names) {
if (initial_map.count(node_name) > 0) {
// Combine parameter yaml files, overwriting values in older ones
for (const rclcpp::Parameter & param : initial_map.at(node_name)) {
parameter_overrides_[param.get_name()] =
rclcpp::ParameterValue(param.get_value_message());
}
}
}
}
}
// parameter overrides passed to constructor will overwrite overrides from yaml file sources
for (auto & param : parameter_overrides) {
parameter_overrides_[param.get_name()] =
rclcpp::ParameterValue(param.get_value_message());
}
// If asked, initialize any parameters that ended up in the initial parameter values,
// but did not get declared explcitily by this point.
if (automatically_declare_parameters_from_overrides) {
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.dynamic_typing = true;
for (const auto & pair : this->get_parameter_overrides()) {
if (!this->has_parameter(pair.first)) {
this->declare_parameter(
pair.first,
pair.second,
descriptor,
rcl_interfaces::msg::ParameterDescriptor(),
true);
}
}
@@ -136,13 +165,14 @@ __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;
}
static
std::string
format_range_reason(const std::string & name, const char * range_type)
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.";
return ss.str();
reason = ss.str();
}
RCLCPP_LOCAL
@@ -161,7 +191,7 @@ __check_parameter_value_in_range(
}
if ((v < integer_range.from_value) || (v > integer_range.to_value)) {
result.successful = false;
result.reason = format_range_reason(descriptor.name, "integer");
format_reason(result.reason, descriptor.name, "integer");
return result;
}
if (integer_range.step == 0) {
@@ -171,7 +201,7 @@ __check_parameter_value_in_range(
return result;
}
result.successful = false;
result.reason = format_range_reason(descriptor.name, "integer");
format_reason(result.reason, descriptor.name, "integer");
return result;
}
@@ -183,7 +213,7 @@ __check_parameter_value_in_range(
}
if ((v < fp_range.from_value) || (v > fp_range.to_value)) {
result.successful = false;
result.reason = format_range_reason(descriptor.name, "floating point");
format_reason(result.reason, descriptor.name, "floating point");
return result;
}
if (fp_range.step == 0.0) {
@@ -194,62 +224,29 @@ __check_parameter_value_in_range(
return result;
}
result.successful = false;
result.reason = format_range_reason(descriptor.name, "floating point");
format_reason(result.reason, descriptor.name, "floating point");
return result;
}
return result;
}
static
std::string
format_type_reason(
const std::string & name, const std::string & old_type, const std::string & new_type)
{
std::ostringstream ss;
// WARN: A condition later depends on this message starting with "Wrong parameter type",
// check `declare_parameter` if you modify this!
ss << "Wrong parameter type, parameter {" << name << "} is of type {" << old_type <<
"}, setting it to {" << new_type << "} is not allowed.";
return ss.str();
}
// 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,
bool allow_undeclared)
const std::vector<rclcpp::Parameter> & parameters)
{
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
for (const rclcpp::Parameter & parameter : parameters) {
std::string name = parameter.get_name();
rcl_interfaces::msg::ParameterDescriptor descriptor;
if (allow_undeclared) {
auto it = parameter_infos.find(name);
if (it != parameter_infos.cend()) {
descriptor = it->second.descriptor;
} else {
// implicitly declared parameters are dinamically typed!
descriptor.dynamic_typing = true;
}
} else {
descriptor = parameter_infos[name].descriptor;
}
const auto new_type = parameter.get_type();
const auto specified_type = static_cast<rclcpp::ParameterType>(descriptor.type);
result.successful = descriptor.dynamic_typing || specified_type == new_type;
if (!result.successful) {
result.reason = format_type_reason(
name, rclcpp::to_string(specified_type), rclcpp::to_string(new_type));
return result;
}
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) {
return result;
break;
}
}
return result;
@@ -296,18 +293,16 @@ __set_parameters_atomically_common(
const std::vector<rclcpp::Parameter> & parameters,
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameter_infos,
CallbacksContainerType & callback_container,
const OnParametersSetCallbackType & callback,
bool allow_undeclared = false)
const OnParametersSetCallbackType & callback)
{
// Check if the value being set complies with the descriptor.
rcl_interfaces::msg::SetParametersResult result = __check_parameters(
parameter_infos, parameters, allow_undeclared);
// Call the user callback to see if the new value(s) are allowed.
rcl_interfaces::msg::SetParametersResult result =
__call_on_parameters_set_callbacks(parameters, callback_container, callback);
if (!result.successful) {
return result;
}
// Call the user callback to see if the new value(s) are allowed.
result =
__call_on_parameters_set_callbacks(parameters, callback_container, callback);
// Check if the value being set complies with the descriptor.
result = __check_parameters(parameter_infos, parameters);
if (!result.successful) {
return result;
}
@@ -349,21 +344,6 @@ __declare_parameter_common(
initial_value = &overrides_it->second;
}
// If there is no initial value, then skip initialization
if (initial_value->get_type() == rclcpp::PARAMETER_NOT_SET) {
// Add declared parameters to storage (without a value)
parameter_infos[name].descriptor.name = name;
if (parameter_descriptor.dynamic_typing) {
parameter_infos[name].descriptor.type = rclcpp::PARAMETER_NOT_SET;
} else {
parameter_infos[name].descriptor.type = parameter_descriptor.type;
}
parameters_out[name] = parameter_infos.at(name);
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
return result;
}
// 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.
@@ -373,10 +353,6 @@ __declare_parameter_common(
callback_container,
callback);
if (!result.successful) {
return result;
}
// Add declared parameters to storage.
parameters_out[name] = parameter_infos.at(name);
@@ -388,150 +364,54 @@ __declare_parameter_common(
return result;
}
static
const rclcpp::ParameterValue &
declare_parameter_helper(
NodeParameters::declare_parameter(
const std::string & name,
rclcpp::ParameterType type,
const rclcpp::ParameterValue & default_value,
rcl_interfaces::msg::ParameterDescriptor parameter_descriptor,
bool ignore_override,
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameters,
const std::map<std::string, rclcpp::ParameterValue> & overrides,
CallbacksContainerType & callback_container,
const OnParametersSetCallbackType & callback,
rclcpp::Publisher<rcl_interfaces::msg::ParameterEvent> * events_publisher,
const std::string & combined_name,
rclcpp::node_interfaces::NodeClockInterface & node_clock)
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
bool ignore_override)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
// 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)) {
if (__lockless_has_parameter(parameters_, name)) {
throw rclcpp::exceptions::ParameterAlreadyDeclaredException(
"parameter '" + name + "' has already been declared");
}
if (!parameter_descriptor.dynamic_typing) {
if (rclcpp::PARAMETER_NOT_SET == type) {
type = default_value.get_type();
}
if (rclcpp::PARAMETER_NOT_SET == type) {
throw rclcpp::exceptions::InvalidParameterTypeException{
name,
"cannot declare a statically typed parameter with an uninitialized value"
};
}
parameter_descriptor.type = static_cast<uint8_t>(type);
}
rcl_interfaces::msg::ParameterEvent parameter_event;
auto result = __declare_parameter_common(
name,
default_value,
parameter_descriptor,
parameters,
overrides,
callback_container,
callback,
parameters_,
parameter_overrides_,
on_parameters_set_callback_container_,
on_parameters_set_callback_,
&parameter_event,
ignore_override);
// If it failed to be set, then throw an exception.
if (!result.successful) {
constexpr const char type_error_msg_start[] = "Wrong parameter type";
if (
0u == std::strncmp(
result.reason.c_str(), type_error_msg_start, sizeof(type_error_msg_start) - 1))
{
// TODO(ivanpauno): Refactor the logic so we don't need the above `strncmp` and we can
// detect between both exceptions more elegantly.
throw rclcpp::exceptions::InvalidParameterTypeException(name, result.reason);
}
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) {
parameter_event.node = combined_name;
parameter_event.stamp = node_clock.get_clock()->now();
events_publisher->publish(parameter_event);
if (nullptr != events_publisher_) {
parameter_event.node = combined_name_;
parameter_event.stamp = node_clock_->get_clock()->now();
events_publisher_->publish(parameter_event);
}
return parameters.at(name).value;
}
const rclcpp::ParameterValue &
NodeParameters::declare_parameter(const std::string & name)
{
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.dynamic_typing = true;
return this->declare_parameter(name, rclcpp::ParameterValue{}, descriptor, false);
}
const rclcpp::ParameterValue &
NodeParameters::declare_parameter(
const std::string & name,
const rclcpp::ParameterValue & default_value,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
bool ignore_override)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
return declare_parameter_helper(
name,
rclcpp::PARAMETER_NOT_SET,
default_value,
parameter_descriptor,
ignore_override,
parameters_,
parameter_overrides_,
on_parameters_set_callback_container_,
on_parameters_set_callback_,
events_publisher_.get(),
combined_name_,
*node_clock_);
}
const rclcpp::ParameterValue &
NodeParameters::declare_parameter(
const std::string & name,
rclcpp::ParameterType type,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
bool ignore_override)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
if (rclcpp::PARAMETER_NOT_SET == type) {
throw std::invalid_argument{
"declare_parameter(): the provided parameter type cannot be rclcpp::PARAMETER_NOT_SET"};
}
if (parameter_descriptor.dynamic_typing == true) {
throw std::invalid_argument{
"declare_parameter(): cannot declare parameter of specific type and pass descriptor"
"with `dynamic_typing=true`"};
}
return declare_parameter_helper(
name,
type,
rclcpp::ParameterValue{},
parameter_descriptor,
ignore_override,
parameters_,
parameter_overrides_,
on_parameters_set_callback_container_,
on_parameters_set_callback_,
events_publisher_.get(),
combined_name_,
*node_clock_);
return parameters_.at(name).value;
}
void
@@ -551,10 +431,6 @@ NodeParameters::undeclare_parameter(const std::string & name)
throw rclcpp::exceptions::ParameterImmutableException(
"cannot undeclare parameter '" + name + "' because it is read-only");
}
if (!parameter_info->second.descriptor.dynamic_typing) {
throw rclcpp::exceptions::InvalidParameterTypeException{
name, "cannot undeclare an statically typed parameter"};
}
parameters_.erase(parameter_info);
}
@@ -648,17 +524,13 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
rcl_interfaces::msg::ParameterEvent parameter_event_msg;
parameter_event_msg.node = combined_name_;
CallbacksContainerType empty_callback_container;
// Implicit declare uses dynamic type descriptor.
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.dynamic_typing = true;
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(),
descriptor,
rcl_interfaces::msg::ParameterDescriptor(), // Implicit declare uses default descriptor.
staged_parameter_changes,
parameter_overrides_,
// Only call callbacks once below
@@ -707,11 +579,6 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
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()) {
if (!it->second.descriptor.dynamic_typing) {
result.reason = "cannot undeclare an statically typed parameter";
result.successful = false;
return result;
}
parameters_to_be_undeclared.push_back(&parameter);
}
}
@@ -727,8 +594,7 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
on_parameters_set_callback_container_,
// These callbacks are called once. When a callback returns an unsuccessful result,
// the remaining aren't called.
on_parameters_set_callback_,
allow_undeclared_); // allow undeclared
on_parameters_set_callback_);
// If not successful, then stop here.
if (!result.successful) {
@@ -813,21 +679,14 @@ NodeParameters::get_parameters(const std::vector<std::string> & names) const
rclcpp::Parameter
NodeParameters::get_parameter(const std::string & name) const
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
rclcpp::Parameter parameter;
auto param_iter = parameters_.find(name);
if (
parameters_.end() != param_iter &&
(param_iter->second.value.get_type() != rclcpp::ParameterType::PARAMETER_NOT_SET ||
param_iter->second.descriptor.dynamic_typing))
{
return rclcpp::Parameter{name, param_iter->second.value};
if (get_parameter(name, parameter)) {
return parameter;
} else if (this->allow_undeclared_) {
return rclcpp::Parameter{};
} else if (parameters_.end() == param_iter) {
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
return parameter;
} else {
throw rclcpp::exceptions::ParameterUninitializedException(name);
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
}
}
@@ -969,6 +828,22 @@ NodeParameters::list_parameters(const std::vector<std::string> & prefixes, uint6
return result;
}
struct HandleCompare
: public std::unary_function<OnSetParametersCallbackHandle::WeakPtr, bool>
{
explicit HandleCompare(const OnSetParametersCallbackHandle * const base)
: base_(base) {}
bool operator()(const OnSetParametersCallbackHandle::WeakPtr & handle)
{
auto shared_handle = handle.lock();
if (base_ == shared_handle.get()) {
return true;
}
return false;
}
const OnSetParametersCallbackHandle * const base_;
};
void
NodeParameters::remove_on_set_parameters_callback(
const OnSetParametersCallbackHandle * const handle)
@@ -979,9 +854,7 @@ NodeParameters::remove_on_set_parameters_callback(
auto it = std::find_if(
on_parameters_set_callback_container_.begin(),
on_parameters_set_callback_container_.end(),
[handle](const auto & weak_handle) {
return handle == weak_handle.lock().get();
});
HandleCompare(handle));
if (it != on_parameters_set_callback_container_.end()) {
on_parameters_set_callback_container_.erase(it);
} else {

View File

@@ -27,8 +27,7 @@ NodeTimeSource::NodeTimeSource(
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock,
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters,
const rclcpp::QoS & qos,
bool use_clock_thread)
const rclcpp::QoS & qos)
: node_base_(node_base),
node_topics_(node_topics),
node_graph_(node_graph),
@@ -36,7 +35,7 @@ NodeTimeSource::NodeTimeSource(
node_logging_(node_logging),
node_clock_(node_clock),
node_parameters_(node_parameters),
time_source_(qos, use_clock_thread)
time_source_(qos)
{
time_source_.attachNode(
node_base_,

View File

@@ -16,8 +16,6 @@
#include <string>
#include "tracetools/tracetools.h"
using rclcpp::node_interfaces::NodeTimers;
NodeTimers::NodeTimers(rclcpp::node_interfaces::NodeBaseInterface * node_base)
@@ -46,8 +44,4 @@ NodeTimers::add_timer(
std::string("Failed to notify wait set on timer creation: ") +
rmw_get_error_string().str);
}
TRACEPOINT(
rclcpp_timer_link_node,
static_cast<const void *>(timer->get_timer_handle().get()),
static_cast<const void *>(node_base_->get_rcl_node_handle()));
}

View File

@@ -78,7 +78,6 @@ NodeOptions::operator=(const NodeOptions & other)
this->start_parameter_services_ = other.start_parameter_services_;
this->start_parameter_event_publisher_ = other.start_parameter_event_publisher_;
this->clock_qos_ = other.clock_qos_;
this->use_clock_thread_ = other.use_clock_thread_;
this->parameter_event_qos_ = other.parameter_event_qos_;
this->rosout_qos_ = other.rosout_qos_;
this->parameter_event_publisher_options_ = other.parameter_event_publisher_options_;
@@ -273,19 +272,6 @@ NodeOptions::clock_qos(const rclcpp::QoS & clock_qos)
return *this;
}
bool
NodeOptions::use_clock_thread() const
{
return this->use_clock_thread_;
}
NodeOptions &
NodeOptions::use_clock_thread(bool use_clock_thread)
{
this->use_clock_thread_ = use_clock_thread;
return *this;
}
const rclcpp::QoS &
NodeOptions::parameter_event_qos() const
{

View File

@@ -42,7 +42,7 @@ AsyncParametersClient::AsyncParametersClient(
if (remote_node_name != "") {
remote_node_name_ = remote_node_name;
} else {
remote_node_name_ = node_base_interface->get_fully_qualified_name();
remote_node_name_ = node_base_interface->get_name();
}
rcl_client_options_t options = rcl_client_get_default_options();
@@ -144,35 +144,6 @@ AsyncParametersClient::get_parameters(
return future_result;
}
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>>
AsyncParametersClient::describe_parameters(
const std::vector<std::string> & names,
std::function<
void(std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>>)
> callback)
{
auto promise_result =
std::make_shared<std::promise<std::vector<rcl_interfaces::msg::ParameterDescriptor>>>();
auto future_result = promise_result->get_future().share();
auto request = std::make_shared<rcl_interfaces::srv::DescribeParameters::Request>();
request->names = names;
describe_parameters_client_->async_send_request(
request,
[promise_result, future_result, callback](
rclcpp::Client<rcl_interfaces::srv::DescribeParameters>::SharedFuture cb_f)
{
promise_result->set_value(cb_f.get()->descriptors);
if (callback != nullptr) {
callback(future_result);
}
}
);
return future_result;
}
std::shared_future<std::vector<rclcpp::ParameterType>>
AsyncParametersClient::get_parameter_types(
const std::vector<std::string> & names,
@@ -273,55 +244,6 @@ AsyncParametersClient::set_parameters_atomically(
return future_result;
}
std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>
AsyncParametersClient::delete_parameters(
const std::vector<std::string> & parameters_names)
{
std::vector<rclcpp::Parameter> parameters;
for (const std::string & name : parameters_names) {
parameters.push_back(rclcpp::Parameter(name));
}
auto future_result = set_parameters(parameters);
return future_result;
}
std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>
AsyncParametersClient::load_parameters(
const std::string & yaml_filename)
{
rclcpp::ParameterMap parameter_map = rclcpp::parameter_map_from_yaml_file(yaml_filename);
return this->load_parameters(parameter_map);
}
std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>
AsyncParametersClient::load_parameters(
const rclcpp::ParameterMap & parameter_map)
{
std::vector<rclcpp::Parameter> parameters;
std::string remote_name = remote_node_name_.substr(remote_node_name_.substr(1).find("/") + 2);
for (const auto & params : parameter_map) {
std::string node_full_name = params.first;
std::string node_name = node_full_name.substr(node_full_name.find("/*/") + 3);
if (node_full_name == remote_node_name_ ||
node_full_name == "/**" ||
(node_name == remote_name))
{
for (const auto & param : params.second) {
parameters.push_back(param);
}
}
}
if (parameters.size() == 0) {
throw rclcpp::exceptions::InvalidParametersException("No valid parameter");
}
auto future_result = set_parameters(parameters);
return future_result;
}
std::shared_future<rcl_interfaces::msg::ListParametersResult>
AsyncParametersClient::list_parameters(
const std::vector<std::string> & prefixes,
@@ -391,16 +313,14 @@ AsyncParametersClient::wait_for_service_nanoseconds(std::chrono::nanoseconds tim
}
std::vector<rclcpp::Parameter>
SyncParametersClient::get_parameters(
const std::vector<std::string> & parameter_names,
std::chrono::nanoseconds timeout)
SyncParametersClient::get_parameters(const std::vector<std::string> & parameter_names)
{
auto f = async_parameters_client_->get_parameters(parameter_names);
using rclcpp::executors::spin_node_until_future_complete;
if (
spin_node_until_future_complete(
*executor_, node_base_interface_, f,
timeout) == rclcpp::FutureReturnCode::SUCCESS)
*executor_, node_base_interface_,
f) == rclcpp::FutureReturnCode::SUCCESS)
{
return f.get();
}
@@ -417,34 +337,16 @@ SyncParametersClient::has_parameter(const std::string & parameter_name)
return vars.names.size() > 0;
}
std::vector<rcl_interfaces::msg::ParameterDescriptor>
SyncParametersClient::describe_parameters(
const std::vector<std::string> & parameter_names,
std::chrono::nanoseconds timeout)
{
auto f = async_parameters_client_->describe_parameters(parameter_names);
using rclcpp::executors::spin_node_until_future_complete;
rclcpp::FutureReturnCode future =
spin_node_until_future_complete(*executor_, node_base_interface_, f, timeout);
if (future == rclcpp::FutureReturnCode::SUCCESS) {
return f.get();
}
return std::vector<rcl_interfaces::msg::ParameterDescriptor>();
}
std::vector<rclcpp::ParameterType>
SyncParametersClient::get_parameter_types(
const std::vector<std::string> & parameter_names,
std::chrono::nanoseconds timeout)
SyncParametersClient::get_parameter_types(const std::vector<std::string> & parameter_names)
{
auto f = async_parameters_client_->get_parameter_types(parameter_names);
using rclcpp::executors::spin_node_until_future_complete;
if (
spin_node_until_future_complete(
*executor_, node_base_interface_, f,
timeout) == rclcpp::FutureReturnCode::SUCCESS)
*executor_, node_base_interface_,
f) == rclcpp::FutureReturnCode::SUCCESS)
{
return f.get();
}
@@ -453,52 +355,15 @@ SyncParametersClient::get_parameter_types(
std::vector<rcl_interfaces::msg::SetParametersResult>
SyncParametersClient::set_parameters(
const std::vector<rclcpp::Parameter> & parameters,
std::chrono::nanoseconds timeout)
const std::vector<rclcpp::Parameter> & parameters)
{
auto f = async_parameters_client_->set_parameters(parameters);
using rclcpp::executors::spin_node_until_future_complete;
if (
spin_node_until_future_complete(
*executor_, node_base_interface_, f,
timeout) == rclcpp::FutureReturnCode::SUCCESS)
{
return f.get();
}
return std::vector<rcl_interfaces::msg::SetParametersResult>();
}
std::vector<rcl_interfaces::msg::SetParametersResult>
SyncParametersClient::delete_parameters(
const std::vector<std::string> & parameters_names,
std::chrono::nanoseconds timeout)
{
auto f = async_parameters_client_->delete_parameters(parameters_names);
using rclcpp::executors::spin_node_until_future_complete;
if (
spin_node_until_future_complete(
*executor_, node_base_interface_, f,
timeout) == rclcpp::FutureReturnCode::SUCCESS)
{
return f.get();
}
return std::vector<rcl_interfaces::msg::SetParametersResult>();
}
std::vector<rcl_interfaces::msg::SetParametersResult>
SyncParametersClient::load_parameters(
const std::string & yaml_filename,
std::chrono::nanoseconds timeout)
{
auto f = async_parameters_client_->load_parameters(yaml_filename);
using rclcpp::executors::spin_node_until_future_complete;
if (
spin_node_until_future_complete(
*executor_, node_base_interface_, f,
timeout) == rclcpp::FutureReturnCode::SUCCESS)
*executor_, node_base_interface_,
f) == rclcpp::FutureReturnCode::SUCCESS)
{
return f.get();
}
@@ -507,16 +372,15 @@ SyncParametersClient::load_parameters(
rcl_interfaces::msg::SetParametersResult
SyncParametersClient::set_parameters_atomically(
const std::vector<rclcpp::Parameter> & parameters,
std::chrono::nanoseconds timeout)
const std::vector<rclcpp::Parameter> & parameters)
{
auto f = async_parameters_client_->set_parameters_atomically(parameters);
using rclcpp::executors::spin_node_until_future_complete;
if (
spin_node_until_future_complete(
*executor_, node_base_interface_, f,
timeout) == rclcpp::FutureReturnCode::SUCCESS)
*executor_, node_base_interface_,
f) == rclcpp::FutureReturnCode::SUCCESS)
{
return f.get();
}
@@ -527,16 +391,15 @@ SyncParametersClient::set_parameters_atomically(
rcl_interfaces::msg::ListParametersResult
SyncParametersClient::list_parameters(
const std::vector<std::string> & parameter_prefixes,
uint64_t depth,
std::chrono::nanoseconds timeout)
uint64_t depth)
{
auto f = async_parameters_client_->list_parameters(parameter_prefixes, depth);
using rclcpp::executors::spin_node_until_future_complete;
if (
spin_node_until_future_complete(
*executor_, node_base_interface_, f,
timeout) == rclcpp::FutureReturnCode::SUCCESS)
*executor_, node_base_interface_,
f) == rclcpp::FutureReturnCode::SUCCESS)
{
return f.get();
}

View File

@@ -14,7 +14,6 @@
#include "rclcpp/parameter_events_filter.hpp"
#include <memory>
#include <string>
#include <vector>
@@ -23,7 +22,7 @@ using EventType = rclcpp::ParameterEventsFilter::EventType;
using EventPair = rclcpp::ParameterEventsFilter::EventPair;
ParameterEventsFilter::ParameterEventsFilter(
std::shared_ptr<const rcl_interfaces::msg::ParameterEvent> event,
rcl_interfaces::msg::ParameterEvent::SharedPtr event,
const std::vector<std::string> & names,
const std::vector<EventType> & types)
: event_(event)

View File

@@ -19,14 +19,14 @@
#include <utility>
#include <vector>
#include "rclcpp/parameter_event_handler.hpp"
#include "rclcpp/parameter_events_subscriber.hpp"
#include "rcpputils/join.hpp"
namespace rclcpp
{
ParameterEventCallbackHandle::SharedPtr
ParameterEventHandler::add_parameter_event_callback(
ParameterEventsSubscriber::add_parameter_event_callback(
ParameterEventCallbackType callback)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
@@ -37,17 +37,32 @@ ParameterEventHandler::add_parameter_event_callback(
return handle;
}
template<typename CallbackHandleT>
struct HandleCompare
: public std::unary_function<typename CallbackHandleT::WeakPtr, bool>
{
explicit HandleCompare(const CallbackHandleT * const base)
: base_(base) {}
bool operator()(const typename CallbackHandleT::WeakPtr & handle)
{
auto shared_handle = handle.lock();
if (base_ == shared_handle.get()) {
return true;
}
return false;
}
const CallbackHandleT * const base_;
};
void
ParameterEventHandler::remove_parameter_event_callback(
ParameterEventCallbackHandle::SharedPtr callback_handle)
ParameterEventsSubscriber::remove_parameter_event_callback(
const ParameterEventCallbackHandle * const handle)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
auto it = std::find_if(
event_callbacks_.begin(),
event_callbacks_.end(),
[callback_handle](const auto & weak_handle) {
return callback_handle.get() == weak_handle.lock().get();
});
HandleCompare<ParameterEventCallbackHandle>(handle));
if (it != event_callbacks_.end()) {
event_callbacks_.erase(it);
} else {
@@ -56,7 +71,7 @@ ParameterEventHandler::remove_parameter_event_callback(
}
ParameterCallbackHandle::SharedPtr
ParameterEventHandler::add_parameter_callback(
ParameterEventsSubscriber::add_parameter_callback(
const std::string & parameter_name,
ParameterCallbackType callback,
const std::string & node_name)
@@ -75,18 +90,15 @@ ParameterEventHandler::add_parameter_callback(
}
void
ParameterEventHandler::remove_parameter_callback(
ParameterCallbackHandle::SharedPtr callback_handle)
ParameterEventsSubscriber::remove_parameter_callback(
const ParameterCallbackHandle * const handle)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
auto handle = callback_handle.get();
auto & container = parameter_callbacks_[{handle->parameter_name, handle->node_name}];
auto it = std::find_if(
container.begin(),
container.end(),
[handle](const auto & weak_handle) {
return handle == weak_handle.lock().get();
});
HandleCompare<ParameterCallbackHandle>(handle));
if (it != container.end()) {
container.erase(it);
if (container.empty()) {
@@ -98,7 +110,7 @@ ParameterEventHandler::remove_parameter_callback(
}
bool
ParameterEventHandler::get_parameter_from_event(
ParameterEventsSubscriber::get_parameter_from_event(
const rcl_interfaces::msg::ParameterEvent & event,
rclcpp::Parameter & parameter,
const std::string parameter_name,
@@ -126,7 +138,7 @@ ParameterEventHandler::get_parameter_from_event(
}
rclcpp::Parameter
ParameterEventHandler::get_parameter_from_event(
ParameterEventsSubscriber::get_parameter_from_event(
const rcl_interfaces::msg::ParameterEvent & event,
const std::string parameter_name,
const std::string node_name)
@@ -141,7 +153,7 @@ ParameterEventHandler::get_parameter_from_event(
}
std::vector<rclcpp::Parameter>
ParameterEventHandler::get_parameters_from_event(
ParameterEventsSubscriber::get_parameters_from_event(
const rcl_interfaces::msg::ParameterEvent & event)
{
std::vector<rclcpp::Parameter> params;
@@ -158,13 +170,14 @@ ParameterEventHandler::get_parameters_from_event(
}
void
ParameterEventHandler::event_callback(const rcl_interfaces::msg::ParameterEvent & event)
ParameterEventsSubscriber::event_callback(
const rcl_interfaces::msg::ParameterEvent::SharedPtr event)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
for (auto it = parameter_callbacks_.begin(); it != parameter_callbacks_.end(); ++it) {
rclcpp::Parameter p;
if (get_parameter_from_event(event, p, it->first.first, it->first.second)) {
if (get_parameter_from_event(*event, p, it->first.first, it->first.second)) {
for (auto cb = it->second.begin(); cb != it->second.end(); ++cb) {
auto shared_handle = cb->lock();
if (nullptr != shared_handle) {
@@ -187,7 +200,7 @@ ParameterEventHandler::event_callback(const rcl_interfaces::msg::ParameterEvent
}
std::string
ParameterEventHandler::resolve_path(const std::string & path)
ParameterEventsSubscriber::resolve_path(const std::string & path)
{
std::string full_path;

View File

@@ -126,15 +126,3 @@ rclcpp::parameter_value_from(const rcl_variant_t * const c_param_value)
throw InvalidParameterValueException("No parameter value set");
}
ParameterMap
rclcpp::parameter_map_from_yaml_file(const std::string & yaml_filename)
{
rcutils_allocator_t allocator = rcutils_get_default_allocator();
rcl_params_t * rcl_parameters = rcl_yaml_node_struct_init(allocator);
const char * path = yaml_filename.c_str();
if (!rcl_parse_yaml_file(path, rcl_parameters)) {
rclcpp::exceptions::throw_from_rcl_error(RCL_RET_ERROR);
}
return rclcpp::parameter_map_from(rcl_parameters);
}

View File

@@ -41,13 +41,12 @@ ParameterService::ParameterService(
const std::shared_ptr<rcl_interfaces::srv::GetParameters::Request> request,
std::shared_ptr<rcl_interfaces::srv::GetParameters::Response> response)
{
try {
auto parameters = node_params->get_parameters(request->names);
for (const auto & param : parameters) {
response->values.push_back(param.get_value_message());
}
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "Failed to get parameters: %s", ex.what());
for (const auto & name : request->names) {
// Default construct param to NOT_SET
rclcpp::Parameter param;
node_params->get_parameter(name, param);
// push back NOT_SET when get_parameter() call fails
response->values.push_back(param.get_value_message());
}
},
qos_profile, nullptr);
@@ -68,7 +67,7 @@ ParameterService::ParameterService(
return static_cast<rclcpp::ParameterType>(type);
});
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "Failed to get parameter types: %s", ex.what());
RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Failed to get parameter types: %s", ex.what());
}
},
qos_profile, nullptr);
@@ -89,7 +88,7 @@ ParameterService::ParameterService(
result = node_params->set_parameters_atomically(
{rclcpp::Parameter::from_parameter_msg(p)});
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "Failed to set parameter: %s", ex.what());
RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Failed to set parameter: %s", ex.what());
result.successful = false;
result.reason = ex.what();
}
@@ -117,7 +116,7 @@ ParameterService::ParameterService(
auto result = node_params->set_parameters_atomically(pvariants);
response->result = result;
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
RCLCPP_DEBUG(
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 were not declared before setting";
@@ -137,7 +136,7 @@ ParameterService::ParameterService(
auto descriptors = node_params->describe_parameters(request->names);
response->descriptors = descriptors;
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "Failed to describe parameters: %s", ex.what());
RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Failed to describe parameters: %s", ex.what());
}
},
qos_profile, nullptr);

View File

@@ -67,7 +67,7 @@ array_to_string(
type_array << "[";
type_array.setf(format_flags, std::ios_base::basefield | std::ios::boolalpha);
type_array << std::showbase;
for (const ValType & value : array) {
for (const ValType value : array) {
if (!first_item) {
type_array << ", ";
} else {

View File

@@ -34,7 +34,6 @@
#include "rclcpp/experimental/intra_process_manager.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/network_flow_endpoint.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/qos_event.hpp"
@@ -269,39 +268,3 @@ PublisherBase::default_incompatible_qos_callback(
get_topic_name(),
policy_name.c_str());
}
std::vector<rclcpp::NetworkFlowEndpoint> PublisherBase::get_network_flow_endpoints() const
{
rcutils_allocator_t allocator = rcutils_get_default_allocator();
rcl_network_flow_endpoint_array_t network_flow_endpoint_array =
rcl_get_zero_initialized_network_flow_endpoint_array();
rcl_ret_t ret = rcl_publisher_get_network_flow_endpoints(
publisher_handle_.get(), &allocator, &network_flow_endpoint_array);
if (RCL_RET_OK != ret) {
auto error_msg = std::string("error obtaining network flows of publisher: ") +
rcl_get_error_string().str;
rcl_reset_error();
if (RCL_RET_OK !=
rcl_network_flow_endpoint_array_fini(&network_flow_endpoint_array))
{
error_msg += std::string(", also error cleaning up network flow array: ") +
rcl_get_error_string().str;
rcl_reset_error();
}
rclcpp::exceptions::throw_from_rcl_error(ret, error_msg);
}
std::vector<rclcpp::NetworkFlowEndpoint> network_flow_endpoint_vector;
for (size_t i = 0; i < network_flow_endpoint_array.size; ++i) {
network_flow_endpoint_vector.push_back(
rclcpp::NetworkFlowEndpoint(
network_flow_endpoint_array.network_flow_endpoint[i]));
}
ret = rcl_network_flow_endpoint_array_fini(&network_flow_endpoint_array);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret, "error cleaning up network flow array");
}
return network_flow_endpoint_vector;
}

View File

@@ -16,9 +16,7 @@
#include <string>
#include "rmw/error_handling.h"
#include "rmw/types.h"
#include "rmw/qos_profiles.h"
namespace rclcpp
{
@@ -101,13 +99,6 @@ QoS::history(rmw_qos_history_policy_t history)
return *this;
}
QoS &
QoS::history(HistoryPolicy history)
{
rmw_qos_profile_.history = static_cast<rmw_qos_history_policy_t>(history);
return *this;
}
QoS &
QoS::keep_last(size_t depth)
{
@@ -131,13 +122,6 @@ QoS::reliability(rmw_qos_reliability_policy_t reliability)
return *this;
}
QoS &
QoS::reliability(ReliabilityPolicy reliability)
{
rmw_qos_profile_.reliability = static_cast<rmw_qos_reliability_policy_t>(reliability);
return *this;
}
QoS &
QoS::reliable()
{
@@ -157,13 +141,6 @@ QoS::durability(rmw_qos_durability_policy_t durability)
return *this;
}
QoS &
QoS::durability(DurabilityPolicy durability)
{
rmw_qos_profile_.durability = static_cast<rmw_qos_durability_policy_t>(durability);
return *this;
}
QoS &
QoS::durability_volatile()
{
@@ -209,14 +186,6 @@ QoS::liveliness(rmw_qos_liveliness_policy_t liveliness)
return *this;
}
QoS &
QoS::liveliness(LivelinessPolicy liveliness)
{
rmw_qos_profile_.liveliness = static_cast<rmw_qos_liveliness_policy_t>(liveliness);
return *this;
}
QoS &
QoS::liveliness_lease_duration(rmw_time_t liveliness_lease_duration)
{
@@ -237,51 +206,6 @@ QoS::avoid_ros_namespace_conventions(bool avoid_ros_namespace_conventions)
return *this;
}
HistoryPolicy
QoS::history() const
{
return static_cast<HistoryPolicy>(rmw_qos_profile_.history);
}
size_t
QoS::depth() const {return rmw_qos_profile_.depth;}
ReliabilityPolicy
QoS::reliability() const
{
return static_cast<ReliabilityPolicy>(rmw_qos_profile_.reliability);
}
DurabilityPolicy
QoS::durability() const
{
return static_cast<DurabilityPolicy>(rmw_qos_profile_.durability);
}
Duration
QoS::deadline() const {return Duration::from_rmw_time(rmw_qos_profile_.deadline);}
Duration
QoS::lifespan() const {return Duration::from_rmw_time(rmw_qos_profile_.lifespan);}
LivelinessPolicy
QoS::liveliness() const
{
return static_cast<LivelinessPolicy>(rmw_qos_profile_.liveliness);
}
Duration
QoS::liveliness_lease_duration() const
{
return Duration::from_rmw_time(rmw_qos_profile_.liveliness_lease_duration);
}
bool
QoS::avoid_ros_namespace_conventions() const
{
return rmw_qos_profile_.avoid_ros_namespace_conventions;
}
namespace
{
/// Check if two rmw_time_t have the same values.
@@ -311,45 +235,6 @@ bool operator!=(const QoS & left, const QoS & right)
return !(left == right);
}
QoSCheckCompatibleResult
qos_check_compatible(const QoS & publisher_qos, const QoS & subscription_qos)
{
rmw_qos_compatibility_type_t compatible;
const size_t reason_size = 2048u;
char reason_c_str[reason_size] = "";
rmw_ret_t ret = rmw_qos_profile_check_compatible(
publisher_qos.get_rmw_qos_profile(),
subscription_qos.get_rmw_qos_profile(),
&compatible,
reason_c_str,
reason_size);
if (RMW_RET_OK != ret) {
std::string error_str(rmw_get_error_string().str);
rmw_reset_error();
throw rclcpp::exceptions::QoSCheckCompatibleException{error_str};
}
QoSCheckCompatibleResult result;
result.reason = std::string(reason_c_str);
switch (compatible) {
case RMW_QOS_COMPATIBILITY_OK:
result.compatibility = QoSCompatibility::Ok;
break;
case RMW_QOS_COMPATIBILITY_WARNING:
result.compatibility = QoSCompatibility::Warning;
break;
case RMW_QOS_COMPATIBILITY_ERROR:
result.compatibility = QoSCompatibility::Error;
break;
default:
throw rclcpp::exceptions::QoSCheckCompatibleException{
"Unexpected compatibility value returned by rmw '" + std::to_string(compatible) +
"'"};
}
return result;
}
ClockQoS::ClockQoS(const QoSInitialization & qos_initialization)
// Using `rmw_qos_profile_sensor_data` intentionally.
// It's best effort and `qos_initialization` is overriding the depth to 1.

View File

@@ -243,7 +243,7 @@ SignalHandler::deferred_signal_handler()
get_logger(),
"deferred_signal_handler(): "
"shutting down rclcpp::Context @ %p, because it had shutdown_on_sigint == true",
static_cast<void *>(context_ptr.get()));
context_ptr.get());
context_ptr->shutdown("signal handler");
}
}

View File

@@ -288,40 +288,3 @@ SubscriptionBase::exchange_in_use_by_wait_set_state(
}
throw std::runtime_error("given pointer_to_subscription_part does not match any part");
}
std::vector<rclcpp::NetworkFlowEndpoint> SubscriptionBase::get_network_flow_endpoints() const
{
rcutils_allocator_t allocator = rcutils_get_default_allocator();
rcl_network_flow_endpoint_array_t network_flow_endpoint_array =
rcl_get_zero_initialized_network_flow_endpoint_array();
rcl_ret_t ret = rcl_subscription_get_network_flow_endpoints(
subscription_handle_.get(), &allocator, &network_flow_endpoint_array);
if (RCL_RET_OK != ret) {
auto error_msg = std::string("Error obtaining network flows of subscription: ") +
rcl_get_error_string().str;
rcl_reset_error();
if (RCL_RET_OK !=
rcl_network_flow_endpoint_array_fini(&network_flow_endpoint_array))
{
error_msg += std::string(". Also error cleaning up network flow array: ") +
rcl_get_error_string().str;
rcl_reset_error();
}
rclcpp::exceptions::throw_from_rcl_error(ret, error_msg);
}
std::vector<rclcpp::NetworkFlowEndpoint> network_flow_endpoint_vector;
for (size_t i = 0; i < network_flow_endpoint_array.size; ++i) {
network_flow_endpoint_vector.push_back(
rclcpp::NetworkFlowEndpoint(
network_flow_endpoint_array.
network_flow_endpoint[i]));
}
ret = rcl_network_flow_endpoint_array_fini(&network_flow_endpoint_array);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret, "error cleaning up network flow array");
}
return network_flow_endpoint_vector;
}

View File

@@ -33,29 +33,21 @@
namespace rclcpp
{
TimeSource::TimeSource(
std::shared_ptr<rclcpp::Node> node,
const rclcpp::QoS & qos,
bool use_clock_thread)
: use_clock_thread_(use_clock_thread),
logger_(rclcpp::get_logger("rclcpp")),
TimeSource::TimeSource(std::shared_ptr<rclcpp::Node> node, const rclcpp::QoS & qos)
: logger_(rclcpp::get_logger("rclcpp")),
qos_(qos)
{
this->attachNode(node);
}
TimeSource::TimeSource(
const rclcpp::QoS & qos,
bool use_clock_thread)
: use_clock_thread_(use_clock_thread),
logger_(rclcpp::get_logger("rclcpp")),
TimeSource::TimeSource(const rclcpp::QoS & qos)
: logger_(rclcpp::get_logger("rclcpp")),
qos_(qos)
{
}
void TimeSource::attachNode(rclcpp::Node::SharedPtr node)
{
use_clock_thread_ = node->get_node_options().use_clock_thread();
attachNode(
node->get_node_base_interface(),
node->get_node_topics_interface(),
@@ -135,7 +127,7 @@ void TimeSource::attachNode(
void TimeSource::detachNode()
{
this->ros_time_active_ = false;
destroy_clock_sub();
clock_subscription_.reset();
parameter_subscription_.reset();
node_base_.reset();
node_topics_.reset();
@@ -216,7 +208,7 @@ void TimeSource::set_clock(
}
}
void TimeSource::clock_cb(std::shared_ptr<const rosgraph_msgs::msg::Clock> msg)
void TimeSource::clock_cb(const rosgraph_msgs::msg::Clock::SharedPtr msg)
{
if (!this->ros_time_active_ && SET_TRUE == this->parameter_state_) {
enable_ros_time();
@@ -241,61 +233,21 @@ void TimeSource::create_clock_sub()
return;
}
rclcpp::SubscriptionOptions options;
options.qos_overriding_options = rclcpp::QosOverridingOptions(
{
rclcpp::QosPolicyKind::Depth,
rclcpp::QosPolicyKind::Durability,
rclcpp::QosPolicyKind::History,
rclcpp::QosPolicyKind::Reliability,
});
if (use_clock_thread_) {
clock_callback_group_ = node_base_->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive,
false
);
options.callback_group = clock_callback_group_;
rclcpp::ExecutorOptions exec_options;
exec_options.context = node_base_->get_context();
clock_executor_ =
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(exec_options);
if (!clock_executor_thread_.joinable()) {
cancel_clock_executor_promise_ = std::promise<void>{};
clock_executor_thread_ = std::thread(
[this]() {
auto future = cancel_clock_executor_promise_.get_future();
clock_executor_->add_callback_group(clock_callback_group_, node_base_);
clock_executor_->spin_until_future_complete(future);
}
);
}
}
clock_subscription_ = rclcpp::create_subscription<rosgraph_msgs::msg::Clock>(
node_parameters_,
node_topics_,
"/clock",
rclcpp::QoS(KeepLast(1)).best_effort(),
std::bind(&TimeSource::clock_cb, this, std::placeholders::_1),
options
std::bind(&TimeSource::clock_cb, this, std::placeholders::_1)
);
}
void TimeSource::destroy_clock_sub()
{
std::lock_guard<std::mutex> guard(clock_sub_lock_);
if (clock_executor_thread_.joinable()) {
cancel_clock_executor_promise_.set_value();
clock_executor_->cancel();
clock_executor_thread_.join();
clock_executor_->remove_callback_group(clock_callback_group_);
}
clock_subscription_.reset();
}
void TimeSource::on_parameter_event(
std::shared_ptr<const rcl_interfaces::msg::ParameterEvent> event)
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()) {

View File

@@ -1,136 +0,0 @@
// Copyright 2018, Bosch Software Innovations GmbH.
// Copyright 2021, Apex.AI 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/typesupport_helpers.hpp"
#include <functional>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <string>
#include <tuple>
#include <utility>
#include "ament_index_cpp/get_package_prefix.hpp"
#include "ament_index_cpp/get_resources.hpp"
#include "rcpputils/shared_library.hpp"
#include "rcpputils/find_library.hpp"
#include "rosidl_runtime_cpp/message_type_support_decl.hpp"
namespace rclcpp
{
namespace
{
// Look for the library in the ament prefix paths.
std::string get_typesupport_library_path(
const std::string & package_name, const std::string & typesupport_identifier)
{
const char * dynamic_library_folder;
#ifdef _WIN32
dynamic_library_folder = "/bin/";
#elif __APPLE__
dynamic_library_folder = "/lib/";
#else
dynamic_library_folder = "/lib/";
#endif
std::string package_prefix;
try {
package_prefix = ament_index_cpp::get_package_prefix(package_name);
} catch (ament_index_cpp::PackageNotFoundError & e) {
throw std::runtime_error(e.what());
}
const std::string library_path = rcpputils::path_for_library(
package_prefix + dynamic_library_folder,
package_name + "__" + typesupport_identifier);
if (library_path.empty()) {
throw std::runtime_error(
"Typesupport library for " + package_name + " does not exist in '" + package_prefix +
"'.");
}
return library_path;
}
std::tuple<std::string, std::string, std::string>
extract_type_identifier(const std::string & full_type)
{
char type_separator = '/';
auto sep_position_back = full_type.find_last_of(type_separator);
auto sep_position_front = full_type.find_first_of(type_separator);
if (sep_position_back == std::string::npos ||
sep_position_back == 0 ||
sep_position_back == full_type.length() - 1)
{
throw std::runtime_error(
"Message type is not of the form package/type and cannot be processed");
}
std::string package_name = full_type.substr(0, sep_position_front);
std::string middle_module = "";
if (sep_position_back - sep_position_front > 0) {
middle_module =
full_type.substr(sep_position_front + 1, sep_position_back - sep_position_front - 1);
}
std::string type_name = full_type.substr(sep_position_back + 1);
return std::make_tuple(package_name, middle_module, type_name);
}
} // anonymous namespace
std::shared_ptr<rcpputils::SharedLibrary>
get_typesupport_library(const std::string & type, const std::string & typesupport_identifier)
{
auto package_name = std::get<0>(extract_type_identifier(type));
auto library_path = get_typesupport_library_path(package_name, typesupport_identifier);
return std::make_shared<rcpputils::SharedLibrary>(library_path);
}
const rosidl_message_type_support_t *
get_typesupport_handle(
const std::string & type,
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library)
{
std::string package_name;
std::string middle_module;
std::string type_name;
std::tie(package_name, middle_module, type_name) = extract_type_identifier(type);
auto mk_error = [&package_name, &type_name](auto reason) {
std::stringstream rcutils_dynamic_loading_error;
rcutils_dynamic_loading_error <<
"Something went wrong loading the typesupport library for message type " << package_name <<
"/" << type_name << ". " << reason;
return rcutils_dynamic_loading_error.str();
};
try {
std::string symbol_name = typesupport_identifier + "__get_message_type_support_handle__" +
package_name + "__" + (middle_module.empty() ? "msg" : middle_module) + "__" + type_name;
const rosidl_message_type_support_t * (* get_ts)() = nullptr;
// This will throw runtime_error if the symbol was not found.
get_ts = reinterpret_cast<decltype(get_ts)>(library.get_symbol(symbol_name));
return get_ts();
} catch (std::runtime_error &) {
throw std::runtime_error{mk_error("Library could not be found.")};
}
}
} // namespace rclcpp

View File

@@ -4,8 +4,6 @@ find_package(test_msgs REQUIRED)
include(cmake/rclcpp_add_build_failure_test.cmake)
set(TEST_RESOURCES_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/resources")
add_subdirectory(benchmark)
add_subdirectory(rclcpp)
@@ -13,3 +11,8 @@ ament_add_gtest(test_rclcpp_gtest_macros utils/test_rclcpp_gtest_macros.cpp)
if(TARGET test_rclcpp_gtest_macros)
target_link_libraries(test_rclcpp_gtest_macros ${PROJECT_NAME})
endif()
# Install test resources
install(
DIRECTORY resources
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

View File

@@ -42,7 +42,7 @@ public:
nodes[i]->create_publisher<test_msgs::msg::Empty>(
"/empty_msgs_" + std::to_string(i), rclcpp::QoS(10)));
auto callback = [this](test_msgs::msg::Empty::ConstSharedPtr) {this->callback_count++;};
auto callback = [this](test_msgs::msg::Empty::SharedPtr) {this->callback_count++;};
subscriptions.push_back(
nodes[i]->create_subscription<test_msgs::msg::Empty>(
"/empty_msgs_" + std::to_string(i), rclcpp::QoS(10), std::move(callback)));

View File

@@ -46,9 +46,7 @@ BENCHMARK_F(NodePerformanceTest, create_node)(benchmark::State & state)
for (auto _ : state) {
// Using pointer to separate construction and destruction in timing
auto node = std::make_shared<rclcpp::Node>("node");
#ifndef __clang_analyzer__
benchmark::DoNotOptimize(node);
#endif
benchmark::ClobberMemory();
// Ensure destruction of node is not counted toward timing
@@ -71,9 +69,7 @@ BENCHMARK_F(NodePerformanceTest, destroy_node)(benchmark::State & state)
auto node = std::make_shared<rclcpp::Node>("node");
state.ResumeTiming();
#ifndef __clang_analyzer__
benchmark::DoNotOptimize(node);
#endif
benchmark::ClobberMemory();
node.reset();

View File

@@ -30,7 +30,6 @@ public:
param2_name(param_prefix + ".my_param_2"),
param3_name(param_prefix + ".my_param_3")
{
dynamically_typed_descriptor.dynamic_typing = true;
}
void SetUp(benchmark::State & state)
@@ -38,12 +37,9 @@ public:
rclcpp::init(0, nullptr);
node = std::make_shared<rclcpp::Node>(node_name);
node->declare_parameter(
param1_name, rclcpp::ParameterValue{}, dynamically_typed_descriptor);
node->declare_parameter(
param2_name, rclcpp::ParameterValue{}, dynamically_typed_descriptor);
node->declare_parameter(
param3_name, rclcpp::ParameterValue{}, dynamically_typed_descriptor);
node->declare_parameter(param1_name);
node->declare_parameter(param2_name);
node->declare_parameter(param3_name);
node->undeclare_parameter(param3_name);
performance_test_fixture::PerformanceTest::SetUp(state);
@@ -62,7 +58,6 @@ public:
const std::string param1_name;
const std::string param2_name;
const std::string param3_name;
rcl_interfaces::msg::ParameterDescriptor dynamically_typed_descriptor;
protected:
rclcpp::Node::SharedPtr node;
@@ -71,7 +66,7 @@ protected:
BENCHMARK_F(NodeParametersInterfaceTest, declare_undeclare)(benchmark::State & state)
{
for (auto _ : state) {
node->declare_parameter(param3_name, rclcpp::ParameterValue{}, dynamically_typed_descriptor);
node->declare_parameter(param3_name);
node->undeclare_parameter(param3_name);
}
}

View File

@@ -91,14 +91,11 @@ public:
rclcpp::init(0, nullptr);
node = std::make_shared<rclcpp::Node>(node_name);
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.dynamic_typing = true;
remote_node->declare_parameter(
param1_name, rclcpp::ParameterValue("param1_value"), descriptor);
param1_name, rclcpp::ParameterValue("param1_value"));
remote_node->declare_parameter(
param2_name, rclcpp::ParameterValue(std::vector<int> {1, 2, 3}), descriptor);
remote_node->declare_parameter(param3_name, rclcpp::ParameterValue{}, descriptor);
param2_name, rclcpp::ParameterValue(std::vector<int> {1, 2, 3}));
remote_node->declare_parameter(param3_name);
remote_node->undeclare_parameter(param3_name);
params_client = std::make_shared<rclcpp::SyncParametersClient>(node, remote_node_name);

View File

@@ -2,7 +2,7 @@ find_package(ament_cmake_gtest REQUIRED)
find_package(rmw_implementation_cmake REQUIRED)
add_definitions(-DTEST_RESOURCES_DIRECTORY="${TEST_RESOURCES_DIRECTORY}")
add_definitions(-DTEST_RESOURCES_DIRECTORY="${CMAKE_CURRENT_BINARY_DIR}/../resources")
rosidl_generate_interfaces(${PROJECT_NAME}_test_msgs
../msg/Header.msg
@@ -143,13 +143,6 @@ if(TARGET test_intra_process_manager)
)
target_link_libraries(test_intra_process_manager ${PROJECT_NAME})
endif()
ament_add_gmock(test_intra_process_manager_with_allocators test_intra_process_manager_with_allocators.cpp)
if(TARGET test_intra_process_manager_with_allocators)
ament_target_dependencies(test_intra_process_manager_with_allocators
"test_msgs"
)
target_link_libraries(test_intra_process_manager_with_allocators ${PROJECT_NAME})
endif()
ament_add_gtest(test_ring_buffer_implementation test_ring_buffer_implementation.cpp)
if(TARGET test_ring_buffer_implementation)
ament_target_dependencies(test_ring_buffer_implementation
@@ -330,15 +323,15 @@ if(TARGET test_parameter)
)
target_link_libraries(test_parameter ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_event_handler test_parameter_event_handler.cpp)
if(TARGET test_parameter_event_handler)
ament_target_dependencies(test_parameter_event_handler
ament_add_gtest(test_parameter_events_subscriber test_parameter_events_subscriber.cpp)
if(TARGET test_parameter_events_subscriber)
ament_target_dependencies(test_parameter_events_subscriber
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_parameter_event_handler ${PROJECT_NAME})
target_link_libraries(test_parameter_events_subscriber ${PROJECT_NAME})
endif()
ament_add_gtest(test_parameter_map test_parameter_map.cpp)
if(TARGET test_parameter_map)
@@ -375,21 +368,6 @@ if(TARGET test_qos)
${PROJECT_NAME}
)
endif()
function(test_generic_pubsub_for_rmw_implementation)
set(rmw_implementation_env_var RMW_IMPLEMENTATION=${rmw_implementation})
ament_add_gmock(test_generic_pubsub${target_suffix} test_generic_pubsub.cpp
ENV ${rmw_implementation_env_var}
)
if(TARGET test_generic_pubsub${target_suffix})
target_link_libraries(test_generic_pubsub${target_suffix} ${PROJECT_NAME})
ament_target_dependencies(test_generic_pubsub${target_suffix}
"rcpputils"
"rosidl_typesupport_cpp"
"test_msgs"
)
endif()
endfunction()
call_for_each_rmw_implementation(test_generic_pubsub_for_rmw_implementation)
ament_add_gtest(test_qos_event test_qos_event.cpp)
if(TARGET test_qos_event)
ament_target_dependencies(test_qos_event
@@ -495,10 +473,6 @@ if(TARGET test_type_support)
)
target_link_libraries(test_type_support ${PROJECT_NAME})
endif()
ament_add_gmock(test_typesupport_helpers test_typesupport_helpers.cpp)
if(TARGET test_typesupport_helpers)
target_link_libraries(test_typesupport_helpers ${PROJECT_NAME})
endif()
ament_add_gtest(test_find_weak_nodes test_find_weak_nodes.cpp)
if(TARGET test_find_weak_nodes)
ament_target_dependencies(test_find_weak_nodes
@@ -565,6 +539,14 @@ if(TARGET test_utilities)
target_link_libraries(test_utilities ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_init test_init.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_init)
ament_target_dependencies(test_init
"rcl")
target_link_libraries(test_init ${PROJECT_NAME})
endif()
ament_add_gtest(test_interface_traits test_interface_traits.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_interface_traits)

View File

@@ -23,9 +23,7 @@ TEST(TestAllocatorCommon, retyped_allocate) {
void * untyped_allocator = &allocator;
void * allocated_mem =
rclcpp::allocator::retyped_allocate<std::allocator<char>>(1u, untyped_allocator);
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
ASSERT_TRUE(nullptr != allocated_mem);
ASSERT_NE(nullptr, allocated_mem);
auto code = [&untyped_allocator, allocated_mem]() {
rclcpp::allocator::retyped_deallocate<int, std::allocator<int>>(
@@ -34,15 +32,11 @@ TEST(TestAllocatorCommon, retyped_allocate) {
EXPECT_NO_THROW(code());
allocated_mem = allocator.allocate(1);
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
ASSERT_TRUE(nullptr != allocated_mem);
ASSERT_NE(nullptr, allocated_mem);
void * reallocated_mem =
rclcpp::allocator::retyped_reallocate<int, std::allocator<int>>(
allocated_mem, 2u, untyped_allocator);
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
ASSERT_TRUE(nullptr != reallocated_mem);
ASSERT_NE(nullptr, reallocated_mem);
auto code2 = [&untyped_allocator, reallocated_mem]() {
rclcpp::allocator::retyped_deallocate<int, std::allocator<int>>(

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