Compare commits

...

602 Commits

Author SHA1 Message Date
CY Chen
0b4d3d01c6 Add acceptable_buffer_backends field in SubscriptionOptionsBase
Signed-off-by: CY Chen <cyc@nvidia.com>
2026-03-16 17:19:13 +00:00
Danil
b6e9b4c9b4 Expose ServiceType in Service public API (#3088)
Signed-off-by: Danil <danil.nev@gmail.com>
2026-03-12 09:53:26 -07:00
solo
8cd4d47ec5 Avoid unecessary creation of MultiThreadedExecutor (#3090)
Signed-off-by: solonovamax <solonovamax@12oclockpoint.com>
2026-03-12 15:59:22 +01:00
Janosch Machowinski
f145c9ee04 perf: Optimized out shared_ptr copies (#3079)
* perf: Optimized out shared_ptr copies

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* chore: indentation

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

---------

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <j.machowinski@cellumation.com>
2026-03-03 13:43:55 +01:00
Tomoya Fujita
dea57660b5 avoid stale parameter events in content filter tests. (#3085)
* avoid stale parameter events in content filter tests.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* honor the test purpose to call add_parameter_callback().

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* make cpplint happy.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2026-03-03 09:00:58 +09:00
Tomoya Fujita
aea98d665a improve lookup time for matches_any_publishers() (#3084)
* Reapply "improve lookup time for matches_any_publishers(). (#3068)" (#3077)

This reverts commit 1bf4e6a810.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* a few extra fixes to harden the hash map lookup.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* add missing include.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2026-02-27 08:01:28 +09:00
Julien Enoch
87be5fbfd4 Add tests isolation (#3081)
Signed-off-by: Julien Enoch <julien.e@zettascale.tech>
2026-02-21 16:49:21 +09:00
Tomoya Fujita
1bf4e6a810 Revert "improve lookup time for matches_any_publishers(). (#3068)" (#3077)
This reverts commit b6730f9d4e.

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2026-02-20 12:16:35 +01:00
pum1k
fc1afcb3bc Fix component registering in subdirectories (#3064)
Signed-off-by: pum1k <55055380+pum1k@users.noreply.github.com>
2026-02-19 10:03:08 +01:00
Tomoya Fujita
b6730f9d4e improve lookup time for matches_any_publishers(). (#3068)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2026-02-18 15:44:33 +01:00
Janosch Machowinski
9f79f40621 fix: Use default rcl allocator if allocator is std::allocator (#3058)
* fix: Use default rcl allocator if allocator is std::allocator

This fixes a bunch of warnings if using ASAN / valgrind on newer
OS versions. It also fixed a real bug, as giving the wrong size
on deallocate is undefined behavior according to the C++ standard.

This version of the patch keeps the behavior for users that
specified an own allocator the same and in therefore back portable.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* feat: Provide a way to suppress the deprecation warning

This commit adds the feature, that the user can now specify a method
rcl_allocator_t get_rcl_allocator() on the given allocator. This method
will be called if present, to get the rcl allocator.
If the method is not present, the code will fall back to the old
(and faulty) implementation and show a deprecation warning.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

---------

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <j.machowinski@cellumation.com>
2026-02-16 21:20:09 +01:00
Janosch Machowinski
6ff4d83498 fix: Various data races in test cases (#3057)
Signed-off-by: Janosch Machowinski <j.machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <j.machowinski@cellumation.com>
2026-02-11 22:25:06 +01:00
Janosch Machowinski
4d950baa15 fix: Fix data race in CallbackGroup::size() (#3056)
The computation of the size was not protected by a mutex, leading
to possible data races.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2026-02-11 18:05:09 +01:00
Alejandro Hernandez Cordero
866c56d153 30.1.5 2026-02-09 13:28:44 +01:00
Alejandro Hernandez Cordero
6a244e3305 Changelog
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2026-02-09 13:28:42 +01:00
Jasper van Brakel
bddd6105c2 Compatiblity with 'Populate Transitions' ros2/rcl#1269 (#2967)
Signed-off-by: SuperJappie08 <36795178+SuperJappie08@users.noreply.github.com>
2026-02-04 09:10:38 +09:00
YuJin Hong
38cfc4c215 Add library dependency to node executable in rclcpp_components_register_node (#3047)
Fixes #2868

The executable created by rclcpp_components_register_node now depends on
the library target, ensuring the library is rebuilt when the executable
is rebuilt.

Added SKIP_LIBRARY_DEPENDENCY option for cases where the plugin is
provided by a different package.

Signed-off-by: dbwls99706 <yujinhong3@gmail.com>
2026-02-02 14:29:47 +01:00
Tomoya Fujita
b009212508 remove default: so that compiler can detect the missing case. (#3048)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2026-02-02 12:31:55 +01:00
Tomoya Fujita
c7065f7f34 use weak_ptr for rcl entities in the memory strategy. (#2988)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2026-02-01 13:26:38 +09:00
Tomoya Fujita
db7469798f remove test_static_executor_entities_collector.cpp (#3041)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2026-01-30 08:48:08 +09:00
Tomoya Fujita
5ac7f1f024 include the 1st spin that might throw the exception. (#3042)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2026-01-29 18:17:22 +01:00
Tomoya Fujita
f8a7ace7a8 print warning message on owner node if the parameter operation fails. (#3037)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2026-01-28 08:22:17 +09:00
Rahat Dhande
fcc505f453 fix context in wait for message wait set (#3030)
Signed-off-by: Rahat Dhande <rahatchd@gmail.com>
2026-01-22 14:38:37 +01:00
Michael Carroll
841a4632a4 Revert "construct wait set with passed in context (#3021)" (#3028)
This reverts commit cd86362f75.
2026-01-22 07:41:27 +09:00
Rahat Dhande
cd86362f75 construct wait set with passed in context (#3021) 2026-01-21 14:24:10 +01:00
Andrei Costinescu
6397047d47 Update exception documentation for goal cancellation in ServerGoalHandle (#3019)
* Update exception documentation for goal cancellation

The documentation for the canceled function is misleading.
Previously, the description said: 
1. "Only call this if the goal is canceling." and 
2. "\throws rclcpp::exceptions::RCLError If the goal is in any state besides executing."
This is a contradiction.
Experimentally verified that if the goal is executing and this method is called, an error is thrown. This makes the second statement wrong => correct the statement in the documentation.

Signed-off-by: Andrei Costinescu <AndreiCostinescu@users.noreply.github.com>
2026-01-20 09:57:19 +01:00
Barry Xu
7f783cbf58 Improve the robustness of the TopicEndpointInfo constructor (#3013)
* Improve the robustness of the TopicEndpointInfo constructor

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Improve TopicEndpointInfo constructor to validate input parameters

Signed-off-by: Barry Xu <barry.xu@sony.com>

---------

Signed-off-by: Barry Xu <barry.xu@sony.com>
2026-01-10 15:35:59 +01:00
Maurice Alexander Purnawan
c85ff926d2 Deprecate the shared_ptr<MessageT> subscription callback signatures (#2975)
Signed-off-by: mini-1235 <mauricepurnawan@gmail.com>
2025-12-26 17:03:47 +01:00
Alejandro Hernandez Cordero
a4a72ac544 30.1.4 2025-12-23 11:05:21 +01:00
Alejandro Hernandez Cordero
4e166cbed3 Changelog
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-12-23 11:05:17 +01:00
Alejandro Hernández Cordero
6cbb994aca Updated deprecated ament_index_cpp API (#3011)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-12-23 10:27:30 +01:00
fabianhirmann
825b4e4650 Unified Node Interfaces: Add const version of get_node_x_interface() (#3006)
Signed-off-by: Fabian Hirmann <f.hirmann@arti-robots.com>
2025-12-16 10:24:41 +01:00
Lucas Wendland
41c7f68013 Parameter Descriptor Simplification (#2179)
Signed-off-by: CursedRock17 <mtglucas1@gmail.com>
Co-authored-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-12-05 10:13:49 +01:00
Barry Xu
02caec12c3 ParameterEventHandler support ContentFiltering (#2971)
* ParameterEventHandler support ContentFiltering

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Address review comments

Signed-off-by: Barry Xu <barry.xu@sony.com>

---------

Signed-off-by: Barry Xu <barry.xu@sony.com>
2025-12-03 16:45:45 +09:00
Andrianov Roman
87a4cefb83 update policy_name_from_kind && test_qos (#2156)
Signed-off-by: Splinter1984 <rom.andrianov1984@gmail.com>
Co-authored-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-12-01 13:35:41 +01:00
Michael Orlov
d3c95a6a46 Add ability to disable and enable subscription's callbacks (#2985)
* Add disable(enable)_callbacks() API to the subscriptions

Signed-off-by: Michael Orlov <morlovmr@gmail.com>

* Add test coverage for the disable(enable)_calbacks()

Signed-off-by: Michael Orlov <morlovmr@gmail.com>

* Address code review comments. Add missing includes in tests

Signed-off-by: Michael Orlov <morlovmr@gmail.com>

* Don't trace callback in dispatch methods if callbacks are disabled

Signed-off-by: Michael Orlov <morlovmr@gmail.com>

* Protect enable/disable callbacks and callbacks execution with mutex

Reasoning:
 To avoid possible UB when callbacks disabled during callback
 execution and callback handler object deleted while execution hasn't
 been finished yet.

Signed-off-by: Michael Orlov <morlovmr@gmail.com>

* Renames for shadowed callback_mutex_ from the EventHandlerBase

Note: We can't reuse `on_new_event_callback_mutex_` from the
EventHandlerBase because those mutex used to protect another type of
callbacks.

Signed-off-by: Michael Orlov <morlovmr@gmail.com>

* Temporary removes the on_new_[message]event on disable_callbacks()

Note: While we are temporary removes the on new message callback and all
 on new event callbacks from the underlying rmw layer to prevent them
 from being called. We can't guarantee that the currently executing
 on_new_[message]event callbacks are finished before we exit from the
 disable_callbacks().

Signed-off-by: Michael Orlov <morlovmr@gmail.com>

* Use recursive_mutex for callback lock in any_subscription_callback

Signed-off-by: Michael Orlov <morlovmr@gmail.com>

* Address CI warnings about usage of deprecated rclcpp::spin_some(node)

- Use spin_some() from the rclcpp::executors::SingleThreadedExecutor
 directly.

Signed-off-by: Michael Orlov <morlovmr@gmail.com>

---------

Signed-off-by: Michael Orlov <morlovmr@gmail.com>
2025-11-27 11:09:49 -08:00
yadunund
1500449c11 Switch to isolated testing via rmw_test_fixture (#2929)
Signed-off-by: Yadunund <yadunund@gmail.com>
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
Co-authored-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-11-25 10:48:28 +01:00
Tomoya Fujita
95cb964a3b remove I/O from signal handler. (#2986)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-11-19 11:37:04 +01:00
Alejandro Hernandez Cordero
f160024ba4 30.1.3 2025-11-18 11:09:53 +01:00
Alejandro Hernandez Cordero
e6ea37ed5a Changelog
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-11-18 11:09:49 +01:00
Yuchen966
354413c060 correct test function descriptions (#2970)
Signed-off-by: Yuchen Liu <lyuchen9696@gmail.com>
2025-11-17 15:51:23 +01:00
Minju, Lee
63bdf2add4 add : get clients, servers info (#2569)
Signed-off-by: Minju, Lee <dlalswn531@naver.com>
2025-11-17 13:43:50 +01:00
Tim Clephas
ad019b9827 Fix REP url locations (#2987)
This popped up in my global replace

Signed-off-by: Tim Clephas <tim.clephas@nobleo.nl>
2025-11-17 10:01:03 +01:00
Zheng Qu
eb49444c32 Add get_parameter_or overload returning value or alternative (#2973)
Signed-off-by: Zheng Qu <quzhengrobot@gmail.com>
2025-11-07 12:24:01 +01:00
Alejandro Hernandez Cordero
4d14414d91 30.1.2 2025-10-21 11:43:39 +02:00
Alejandro Hernandez Cordero
7fcc7e723c Changelog
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-10-21 11:43:35 +02:00
Tomoya Fujita
db4f9c21de clear handles before node destruction in test_memory_strategy. (#2969)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-10-21 08:50:48 +09:00
Ivo Ivanov
8499404709 Added static assert asserting custom types have no overloaded operator new (#2954)
Signed-off-by: Ivo Ivanov <ivo.ivanov@tha.de>
2025-10-20 09:14:36 +02:00
Skyler Medeiros
715a983c9f Store graph listener inside the context instead of the node graph (#2952)
* factor shutdown hook registration into its own method

Signed-off-by: Skyler Medeiros <smedeiros@irobot.com>

* run ament_uncrustify

Signed-off-by: Skyler Medeiros <smedeiros@irobot.com>

* consistent use of is_shutdown in graph-listener

Signed-off-by: Skyler Medeiros <smedeiros@irobot.com>

* this doesn't actually need to be a separate function

Signed-off-by: Skyler Medeiros <smedeiros@irobot.com>

* whitespace

Signed-off-by: Skyler Medeiros <smedeiros@irobot.com>

* fix typo

Signed-off-by: Skyler Medeiros <smedeiros@irobot.com>

* move graph listener into the context

Signed-off-by: Skyler Medeiros <smedeiros@irobot.com>

* make cpplint happy

Signed-off-by: Skyler Medeiros <smedeiros@irobot.com>

* Update rclcpp/src/rclcpp/context.cpp

Signed-off-by: Skyler Medeiros <smedeiros@irobot.com>

---------

Signed-off-by: Skyler Medeiros <smedeiros@irobot.com>
2025-10-09 10:09:39 +09:00
Tomoya Fujita
cd9099d85b Reapply "Catch the exception from rate.sleep() if the context is invalid. (#2956)" (#2963) (#2964)
This reverts commit 6fbf03945f.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-10-06 17:12:43 +09:00
Tomoya Fujita
6fbf03945f Revert "Catch the exception from rate.sleep() if the context is invalid. (#2956)" (#2963)
This reverts commit 10f0186c6d.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-10-06 11:22:29 +09:00
Tomoya Fujita
10f0186c6d Catch the exception from rate.sleep() if the context is invalid. (#2956)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-10-06 11:16:59 +09:00
Tomoya Fujita
aa60fcf22a it misses the iterator second to lock the weakptr. (#2958)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-09-30 07:56:36 +09:00
Tomoya Fujita
b14af74a4c try aborting before canceling 1st on dtor of ServerGoalHandle. (#2953)
* try aborting before canceling 1st on dtor of ServerGoalHandle.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* address review comments from Copilot AI.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* add missing header file and descriptions in docsection.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-09-16 14:06:05 +09:00
Ilario A. Azzollini
38f4073474 update Time documentation (#2955)
Signed-off-by: ilarioazzollini <ilario.azzollini92@gmail.com>
2025-09-16 06:43:19 +02:00
Alejandro Hernandez Cordero
380866b338 30.1.1 2025-09-11 15:10:23 +02:00
Alejandro Hernandez Cordero
150a0e8ad9 Changelog
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-09-11 15:10:16 +02:00
Alejandro Hernández Cordero
b432df117a Removed warning (#2949)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-09-11 10:57:56 +09:00
Alberto Soragna
3644195892 add note about problems with spin_until_future_complete (#2849)
* add note indicating that spin_until_future_complete should be used only with futures generated by ROS entities

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* fix indentation and improve explanation of consequences

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

---------

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2025-08-26 14:36:02 +02:00
Alberto Soragna
bdab46d64e deprecate rclcpp::spin_some and rclcpp::spin_all (#2848)
* reorder events executor constructor arguments to have the first args match the other executors

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* deprecate rclcpp::spin_some and rclcpp::spin_all

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* use rcpputils to ignore deprecation and remove deprecated APIs from comments

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* fix rclcpp_lifecycle build failures.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* make linters happy

Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>

* fix test_service_introspection

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* fix lifecycle unit-test

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

---------

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-08-26 19:26:34 +09:00
Barry Xu
82696f6e57 Improve the function extract_type_identifier (#2923)
Signed-off-by: Barry Xu <barry.xu@sony.com>
2025-08-18 20:00:45 +02:00
Tim Clephas
e615c7c309 Allow for implicitly convertable loggers as well (#2922)
* Allow for implicitly convertable loggers as well

Signed-off-by: Tim Clephas <tim.clephas@nobleo.nl>

* Test implicitly convertable logger

Signed-off-by: Tim Clephas <tim.clephas@nobleo.nl>

* This can be simplified now

Signed-off-by: Tim Clephas <tim.clephas@nobleo.nl>

* fixup! This can be simplified now

Signed-off-by: Tim Clephas <tim.clephas@nobleo.nl>

---------

Signed-off-by: Tim Clephas <tim.clephas@nobleo.nl>
2025-08-13 10:46:44 +02:00
Peter Mitrano (AR)
37677791ca Clearer warning message, the old one lacked information and was perhaps misleading (#2927)
* change misleading warning message, making it more correct and informative

Signed-off-by: Peter Mitrano (AR) <peter.mitrano@agile-robots.com>

* Fix compile error. Needed to also build rcl from source.

Signed-off-by: Peter Mitrano (AR) <peter.mitrano@agile-robots.com>

* explicitely initialize pointer as null, to adhere to best practice

Signed-off-by: Peter Mitrano (AR) <peter.mitrano@agile-robots.com>

---------

Signed-off-by: Peter Mitrano (AR) <peter.mitrano@agile-robots.com>
2025-08-12 15:01:53 +02:00
Chris Lalancette
a919a6e5ed Cleanup the dependencies in rclcpp_components. (#2918)
The most important change in here is the changes to the package.xml
and the CMakeLists.txt, which now properly export the dependencies
to downstream packages as required.  On those two fronts:

1.  Make sure to add a dependency on rmw, which this package does depend
    on for rmw_request_id_t
2. Make sure to add a dependency on rcl_interfaces, which this package
   also depends on.
3. Export depend class_loader, composition_interfaces, rclcpp,
   rcpputils, and rmw, all of which are exported in the header files.
4. Remove the unnecessary test dependencies on launch_testing and
   std_msgs, neither of which is used.

The rest of the change here is to cleanup the header files to include
what you use everywhere.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2025-08-03 21:22:30 -04:00
Chris Lalancette
b7e4aad091 30.1.0 2025-07-29 21:03:19 +00:00
Chris Lalancette
fb6d43c5e0 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2025-07-29 21:03:12 +00:00
Michiel Leegwater
1f2adc9829 Fix: improve exception context for parameter_value_from (#2917)
Signed-off-by: Michiel Leegwater <mleegwt@users.noreply.github.com>
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2025-07-29 18:50:32 +02:00
mosfet80
6392ee5187 fix cmake deprecation (#2914)
cmake version < then 3.10 is deprecated

Signed-off-by: Mos <realeandrea@yahoo.it>
2025-07-24 08:57:47 +02:00
Patrick Roncagliolo
4fb558ae7b Fix start_type_description_service param handling (#2897)
* Fix `start_type_description_service` param handling

Signed-off-by: Patrick Roncagliolo <ronca.pat@gmail.com>

* Add test

Signed-off-by: Patrick Roncagliolo <ronca.pat@gmail.com>

* Demonstrate different exceptions depending on node options

Signed-off-by: Patrick Roncagliolo <ronca.pat@gmail.com>

* Same exact exception and `what()` message in both cases

Signed-off-by: Patrick Roncagliolo <ronca.pat@gmail.com>

* Uncrustify

Signed-off-by: Patrick Roncagliolo <ronca.pat@gmail.com>

---------

Signed-off-by: Patrick Roncagliolo <ronca.pat@gmail.com>
2025-07-16 15:45:44 -07:00
Sriharsha Ghanta
2fcef70ea7 Add qos parameter for wait_for_message function (#2903)
Signed-off-by: Sriharsha Ghanta <ghanta1996@gmail.com>
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
Co-authored-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-07-16 09:57:12 +02:00
Tomoya Fujita
84c6fb1cfc Fujitatomoya/test append parameter override (#2896)
* add parameter_overrides_with_parameter test.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* no need to template the function signature of append_parameter_override().

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-07-09 14:04:24 -07:00
Michael Orlov
448287b109 Expose typesupport_helpers API needed for the Rosbag2 (#2858)
* Expose extract_type_identifier and get_typesupport_library_path API

- Rationale: We need to use this API in the Rosbag2
- Reference PR https://github.com/ros2/rosbag2/pull/2017 in the Rosbag2

Signed-off-by: Michael Orlov <michael.orlov@apex.ai>

* Use C++ style in doxygen documentation

Signed-off-by: Michael Orlov <michael.orlov@apex.ai>

---------

Signed-off-by: Michael Orlov <michael.orlov@apex.ai>
2025-07-08 15:43:43 -07:00
Christophe Bedard
b6f03db3d4 Remove comment about now-removed StaticSingleThreadedExecutor (#2893)
Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
2025-07-08 22:49:03 +02:00
Patrick Roncagliolo
fa0cf2da31 Add overload of append_parameter_override (#2891)
Signed-off-by: Patrick Roncagliolo <ronca.pat@gmail.com>
2025-07-08 17:18:57 +02:00
Janosch Machowinski
7ebc9e4cae fix: Don't deadlock if removing shutdown callbacks in a shutdown callback (#2886)
Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-07-02 10:40:25 +02:00
Chris Lalancette
05eafed5b2 30.0.0 2025-07-01 15:46:34 +00:00
Chris Lalancette
eac7d1ad68 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2025-07-01 15:46:17 +00:00
Chris Lalancette
5fd85245bb Hand-code logging.hpp (#2870)
With the similar rewrite coming in rcutils logging macros,
this is now required (since the old machinery relied on the
removed code in rcutils).  Regardless, I think this is more
readable and maintainable.

Note that this does *not* remove the python3-empy dependency,
since that is still needed for other things.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2025-07-01 09:59:27 -04:00
Alejandro Hernández Cordero
e677f4cf39 Adressed TODO in node_graph (#2877)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-06-30 13:20:15 +02:00
Mihir Rao
5122c312d4 NEW PR: Add component_container for EventsExecutor (#2885)
* Add component_container for EventsExecutor

Signed-off-by: Mihir Rao <mihirr@nvidia.com>

* Fix build error

Signed-off-by: Mihir Rao <mihirr@nvidia.com>

---------

Signed-off-by: Mihir Rao <mihirr@nvidia.com>
2025-06-28 14:48:20 -07:00
Tomoya Fujita
e6577c6792 fix test_publisher_with_system_default_qos. (#2881)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-06-26 14:00:01 +02:00
Tomoya Fujita
3cc2a0eacf make sure that plugin arg includes the double colon. (#2878)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-06-25 22:05:25 +02:00
Alejandro Hernandez Cordero
5beec9e32b 29.6.1 2025-06-23 16:00:13 +02:00
Alejandro Hernandez Cordero
6ee3a55fc3 Changelog
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-06-23 16:00:09 +02:00
Adam Aposhian
1e95407bdf set thread names by node in component container isolated (#2871)
Signed-off-by: Adam Aposhian <adam.aposhian@fireflyautomatix.com>
2025-06-18 22:57:00 +02:00
keeponoiro
db8d917a12 Replace std::default_random_engine with std::mt19937 (rolling) (#2843)
Signed-off-by: keeponoiro <keeeeeeep@gmail.com>
2025-05-29 15:29:57 -07:00
Michael Orlov
8d44b95d8b Fix for memory leaks in rclcpp::SerializedMessage (#2861)
Signed-off-by: Michael Orlov <morlovmr@gmail.com>
Signed-off-by: Michael Orlov <michael.orlov@apex.ai>
Co-authored-by: kylemarcey <marcey.kyle@gmail.com>
2025-05-29 10:49:17 +02:00
Alejandro Hernández Cordero
df3a303a17 Removed warning test_qos (#2859)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-05-26 22:05:08 +02:00
Alejandro Hernández Cordero
373a63c5e6 Added missing chrono includes (#2854)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-05-23 00:22:27 +02:00
Alejandro Hernández Cordero
6c478834fb get_all_data_impl() does not handle null pointers properly, causing segmentation fault (#2840)
* get_all_data_impl() does not handle null pointers properly, causing segmentation fault

Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>

* Update rclcpp/include/rclcpp/experimental/buffers/ring_buffer_implementation.hpp

Co-authored-by: Janosch Machowinski <jmachowinski@users.noreply.github.com>
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>

* make linters happy

Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>

---------

Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
Co-authored-by: Janosch Machowinski <jmachowinski@users.noreply.github.com>
2025-05-17 15:49:25 +02:00
Alejandro Hernández Cordero
73e9bfb62b QoSInitialization::from_rmw does not validate invalid history policy values, leading to silent failures (#2841)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-05-16 18:56:22 +02:00
Tomoya Fujita
1aaade8976 remove get_notify_guard_condition from NodeBaseInterface. (#2839)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-05-14 09:37:58 -07:00
Alejandro Hernández Cordero
88d8a9e75a Removed deprecated StaticSingleThreadedExecutor (#2835)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-05-12 10:04:32 +02:00
Alejandro Hernández Cordero
4f507751e1 Removed deprecated rcpputils Path (#2834)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-05-06 00:11:49 +02:00
Alex Youngs
7bd14d812c Add range constraints for applicable array parameters (#2828)
Signed-off-by: Alex Youngs <alexyoungs@hatchbed.com>
2025-05-05 14:39:12 +02:00
Michael Carlstrom
e97d569f75 Update RingBufferImplementation to clear internal data. (#2837)
* Fix clear()

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* Update rclcpp/include/rclcpp/experimental/buffers/ring_buffer_implementation.hpp

Co-authored-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

---------

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
Co-authored-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2025-05-04 12:49:21 -07:00
Alejandro Hernández Cordero
f81caaca49 Removed deprecated cancel_sleep_or_wait (#2836)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-05-02 15:10:07 +02:00
Tomoya Fujita
127a10e8c8 introduce rcl_lifecycle_get_transition_label_by_id(). (#2827)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-05-01 13:13:05 -07:00
Christophe Bedard
b1ec85df16 Add missing 's' to 'NodeParametersInterface' in doc/comment (#2831)
Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
2025-04-30 09:41:39 -07:00
Tomoya Fujita
c89a2b1013 subordinate node consistent behavior and update docstring. (#2822)
* subordinate node consistent behavior and update docstring.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* add subnode_parameter_operation test.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* typo fixes.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-04-29 13:41:52 -07:00
Scott K Logan
1a282064a9 29.6.0 2025-04-25 15:04:18 -05:00
Tomoya Fujita
8b9691f42d throws std::invalid_argument if ParameterEvent is NULL. (#2814)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-04-24 10:30:20 -07:00
Alejandro Hernández Cordero
40e3fb78db Removed clang warnings (#2823)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-04-24 19:24:29 +02:00
Scott K Logan
11afffad50 29.5.0 2025-04-18 16:01:12 -05:00
Pedro de Azeredo
8e49befce9 Fix race condition (#2819)
Signed-off-by: pedroazeredo04 <pedro_azeredo@usp.br>
Signed-off-by: Pedro Nogueira <pedro_azeredo@usp.br>
2025-04-18 22:31:36 +02:00
Tanishq Chaudhary
f78ed952b2 remove redundant typesupport check in serialization module (#2808)
Signed-off-by: Tanishq Chaudhary <tanishqchaudhary101010@gmail.com>
2025-04-14 23:37:54 +02:00
Tomoya Fujita
2420c48514 remove get_typesupport_handle implementation. (#2806)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-04-13 21:47:18 -07:00
Tomoya Fujita
c01602f7a6 use NodeParameterInterface instead of /parameter_event to update "use… (#2378)
* use NodeParameterInterface instead of /parameter_event to update "use_sim_time"

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* re-enable ParameterMutationRecursionGuard.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* adjust test cases.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-04-11 09:01:48 -07:00
Tomoya Fujita
6ad551a5cc use std::recursive_mutex for action requests. (#2798)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-04-10 20:43:47 -07:00
Tomoya Fujita
0162861fa1 remove cancel_clock_executor_promise_. (#2797)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2025-04-10 14:26:34 -07:00
Tomoya Fujita
6040228d13 enable parameter update recursively only when QoS override parameters. (#2742)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-04-09 11:32:11 +02:00
Michael Carroll
892cae9915 29.4.0 2025-04-04 13:42:38 +00:00
Michael Carroll
14c8dd1072 Changelog.
Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>
2025-04-04 13:42:12 +00:00
Leander Stephen D'Souza
011b878554 Removed trailing whitespace from the codebase. (#2791)
Signed-off-by: Leander Stephen D'Souza <leanderdsouza1234@gmail.com>
2025-04-03 20:33:36 -07:00
Tomoya Fujita
de4c7fcd77 remove .github/ISSUE_TEMPLATE.md (old version of templates) (#2792)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-03-31 13:42:36 -07:00
Alejandro Hernández Cordero
fb8e1dda25 Remove warning (#2790)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-03-31 15:22:47 +02:00
Abhishek Kashyap
1dfefe5b63 Expanded docstring of get_rmw_qos_profile() (#2787)
* expanded docstring to include info on profile

Signed-off-by: Abhishek Kashyap <abhishek47kashyap@gmail.com>

* more succinct docstring, also restores one-line summary

Signed-off-by: Abhishek Kashyap <abhishek47kashyap@gmail.com>

---------

Signed-off-by: Abhishek Kashyap <abhishek47kashyap@gmail.com>
2025-03-30 11:32:05 -07:00
Tomoya Fujita
ce86ef7e62 Harden rclcpp_action::convert(). (#2786)
* Harden rclcpp_action::convert().

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* update docstring.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-03-29 21:00:41 -07:00
Tomoya Fujita
7b6ee8a2e7 should pull valid transition before trying to change the state. (#2774)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-03-28 13:14:29 +01:00
Alejandro Hernández Cordero
aae375be91 Set envars to run tests with rmw_zenoh_cpp with multicast discovery (#2776)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
Co-authored-by: Yadunund <yadunund@gmail.com>
2025-03-26 11:00:32 +01:00
Janosch Machowinski
1564fc23c6 fix: Compilefix for clang (#2775)
clang does not like :
    __attribute__ ((visibility("default")))
    [[deprecated("Don't like'")]]
while
    [[deprecated("Don't like'")]]
    __attribute__ ((visibility("default")))
is fine...

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2025-03-20 21:49:17 +01:00
Tomoya Fujita
9ff1201ded add exception doc for configure_introspection. (#2773)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-03-19 08:58:41 -07:00
Janosch Machowinski
b9b46c5871 feat: Add ClockWaiter and ClockConditionalVariable (#2691)
* feat: Add ClockWaiter and ClockConditionalVariable

Added two new synchronization primitives to perform waits
using an rclcpp::Clock.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* fix: Deprecate broken API


Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

---------

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2025-03-19 14:40:01 +01:00
Janosch Machowinski
30e61c955d doc: Added warning to not instantiate Clock directly with RCL_ROS_TIME (#2768)
Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Signed-off-by: Janosch Machowinski <jmachowinski@users.noreply.github.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-03-14 15:22:47 -07:00
Barry Xu
687057ffb6 Add new interfaces to enable introspection for action (#2743)
* Add new interfaces to enable intropsection for action

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Correct some comments

Signed-off-by: Barry Xu <barry.xu@sony.com>

---------

Signed-off-by: Barry Xu <barry.xu@sony.com>
2025-03-12 08:27:06 -07:00
Alejandro Hernández Cordero
9db7fa2ccb Use rmw_event_type_is_supported in test_qos_event (#2761)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-03-11 19:39:16 +01:00
mergify[bot]
387bf7bb51 add NO_UNDEFINED_SYMBOLS to rclcpp_components_register_node cmake macro (#2746) (#2764)
Signed-off-by: Jonas Otto <jonas.otto@ipa.fraunhofer.de>
Signed-off-by: Jonas Otto <jonas@jonasotto.com>
(cherry picked from commit c31daa608d)

Co-authored-by: Jonas Otto <jonas@jonasotto.com>
2025-03-11 16:35:49 +01:00
Barry Xu
9db7659dab Implement action generic client (#2759)
Signed-off-by: Barry Xu <barry.xu@sony.com>
2025-03-07 18:01:25 +01:00
Barry Xu
48a4761faa Support action typesupport helper (#2750)
Signed-off-by: Barry Xu <barry.xu@sony.com>
2025-02-28 16:18:49 +01:00
Tomoya Fujita
6c10f941d3 use maybe_unused attribute for the portability. (#2758)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-02-27 10:44:29 +01:00
Janosch Machowinski
9c493c4615 Executor strong reference fix (#2745)
https://github.com/ros2/rclcpp/issues/2678 reported that the executor
was holding strong references to entities during execution. This commit
adds a regression test for this.

* fix(Executor): Don't hold strong references to entities during spin

This fixes a bug, were dropping an entity during a callback would
not prevent further callbacks. Note, there might still be a race
in the case of the mutithreaded executor.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2025-02-19 18:12:09 -06:00
Janosch Machowinski
34cc960124 Cleanup of https://github.com/ros2/rclcpp/pull/2683 (#2714)
Signed-off-by: Janosch Machowinski <j.machowinski@cellumation.com>
2025-02-19 14:23:17 +01:00
Barry Xu
06d400d795 Fix typo in doc section for get_service_typesupport_handle (#2751)
Signed-off-by: Barry Xu <barry.xu@sony.com>
2025-02-19 13:40:31 +01:00
Janosch Machowinski
605251bd71 Test case and fix for for https://github.com/ros2/rclcpp/issues/2652 (#2713)
Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Signed-off-by: Francisco Martín Rico <fmrico@gmail.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Francisco Martín Rico <fmrico@gmail.com>
2025-02-11 11:16:02 -06:00
Janosch Machowinski
f6b80abe4a fix(timer): Delete node, after executor thread terminated (#2737)
This fixes a potential race leading to a segfault. The segfault would
happen, if the tear down of the test would occur before the timer thread
stopped the spinning of the executor.

Also simplifies the test code, as the cancel of the executor is now in
the TearDown().

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2025-02-10 12:45:30 -06:00
Tomoya Fujita
2cc43b3274 update doc section for spin_xxx methods. (#2730)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: William Woodall <william@osrfoundation.org>
2025-02-04 17:37:13 -06:00
Janosch Machowinski
6069c3df10 fix: Expose timers used by rclcpp::Waitables (#2699)
Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2025-01-30 18:04:41 +01:00
Tomoya Fujita
687adf494b use rmw_qos_profile_rosout_default instead of rcl. (#2663)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-01-30 11:12:30 +01:00
Janosch Machowinski
e7afaa636a fix(Executor): Fixed entities not beeing executed after just beeing added (#2724)
Fixes https://github.com/ros2/rclcpp/issues/2589

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2025-01-27 08:53:41 -08:00
Yuyuan Yuan
2d1b770e85 fix: make the loop condition align with the description (#2726)
Signed-off-by: yuanyuyuan <az6980522@gmail.com>
2025-01-14 10:32:17 -08:00
Tomoya Fujita
80768ed14e ComponentManager should just ignore unknown extra argument in the bas… (#2723)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-01-10 10:07:27 +01:00
Tomoya Fujita
9cabd69412 Collect log messages from rcl, and reset. (#2720)
* Collect log messages from rcl, and reset.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* call rcl_reset_error once the error message is collected.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* address CI failure, error is already collected and reset.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-01-07 19:28:02 -08:00
Chris Lalancette
a0a2a067d8 29.3.0 2024-12-20 16:16:13 +00:00
Chris Lalancette
094618a044 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-12-20 16:16:06 +00:00
Jeffery Hsu
f5e08c2d0c Fix transient local IPC publish (#2708)
* Fix transient local publish when inter and intra process communications are both present.

* Apply the fix to TypeAdapted signature

* Add an executor to intra_process_inter_process_mix_transient_local test case to enable inter process publishing test

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-12-20 09:10:32 -05:00
Tomoya Fujita
016cfeac99 apply actual QoS from rmw to the IPC publisher. (#2707)
* apply actual QoS from rmw to the IPC publisher.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* address uncrustify warning.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-12-15 21:46:12 -08:00
Steve Macenski
a13e16e2cb Adding in topic name to logging on IPC issues (#2706)
* Adding in topic name to logging on IPC issues

Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>

* Update test matching output logging

Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>

* adding in single quotes

Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>

---------

Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>
2024-12-14 09:04:55 -08:00
rcp1
aad8cb53ad Add parsing for rest of obvious boolean extra arguments and throw for unsupported ones (#2685)
Signed-off-by: Robin Petereit <robin.petereit@tum.de>
2024-12-13 08:18:41 -06:00
Tomoya Fujita
8c0161a07f fix TestTimeSource.ROS_time_valid_attach_detach. (#2700)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-12-09 13:15:40 -08:00
Patrick Roncagliolo
a7f05a904a Update docstring for rclcpp::Node::now() (#2696)
Signed-off-by: Patrick Roncagliolo <ronca.pat@gmail.com>
2024-12-04 09:24:50 -08:00
Chris Lalancette
d7245365ed Re-enable executor test on rmw_connextdds. (#2693)
It supports the events executor now, so re-enable the test.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-12-03 00:03:03 -08:00
Chris Lalancette
3310f9eaed Fix warnings on Windows. (#2692)
For reasons I admit I do not understand, the deprecation
warnings for StaticSingleThreadedExecutor on Windows
happen when we construct a shared_ptr for it in the tests.
If we construct a regular object, then it is fine.  Luckily
this test does not require a shared_ptr, so just make it
a regular object here, which rixes the warning.

While we are in here, make all of the tests camel case to
be consistent.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-12-03 00:02:37 -08:00
Nathan Wiebe Neufeldt
785a70d604 Make ament_cmake a buildtool dependency (#2689)
* Make ament_cmake a buildtool dependency

The `ament_cmake` package isn't needed at runtime and so should only be
listed as a `buildtool_dependency`, as is done in most other packages.

* Remove the ament_cmake dependency entirely

Since there's already a buildtool dependency on ament_cmake_ros, having
ament_cmake as well is redundant.

Signed-off-by: Nathan Wiebe Neufeldt <nwiebeneufeldt@clearpath.ai>
2024-12-01 19:49:35 -05:00
Chris Lalancette
9984197c29 Omnibus fixes for running tests with Connext. (#2684)
* Omnibus fixes for running tests with Connext.

When running the tests with RTI Connext as the default
RMW, some of the tests are failing.  There are three
different failures fixed here:

1.  Setting the liveliness duration to a value smaller than
a microsecond causes Connext to throw an error.  Set it to
a millisecond.

2.  Using the SystemDefaultsQoS sets the QoS to KEEP_LAST 1.
Connext is somewhat slow in this regard, so it can be the case
that we are overwriting a previous service introspection event
with the next one.  Switch to the ServicesDefaultQoS in the test,
which ensures we will not lose events.

3.  Connext is slow to match publishers and subscriptions.  Thus,
when creating a subscription "on-the-fly", we should wait for the
publisher to match it before expecting the subscription to actually
receive data from it.

With these fixes in place, the test_client_common, test_generic_service,
test_service_introspection, and test_executors tests all pass for
me with rmw_connextdds.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>

* Fixes for executors.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>

* One more fix for services.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>

* More fixes for service_introspection.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>

* More fixes for introspection.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>

---------

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-11-30 11:25:06 -08:00
jmachowinski
e9b1004247 fix(Executor): Fix segfault if callback group is deleted during rmw_wait (#2683)
Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2024-11-30 11:04:52 -08:00
Chris Lalancette
e64627004f Remove CODEOWNERS and the rolling-to-master job. (#2686)
They are both legacy from times past, and are both
no longer serving their intended purposes.  Just remove them.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-11-26 15:51:01 -05:00
Chris Lalancette
83c282a161 29.2.0 2024-11-25 14:38:16 +00:00
Chris Lalancette
226044022a Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-11-25 14:38:05 +00:00
Tomoya Fujita
7e9ff5f4c7 accept custom allocator for LoanedMessage. (#2672)
* accept custom allocator for LoanedMessage.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* move message allocator using directives to public.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-11-21 13:50:59 -08:00
Chris Lalancette
64dd644469 29.1.0 2024-11-20 15:53:57 +00:00
Chris Lalancette
322b5f5d79 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-11-20 15:53:48 +00:00
Tomoya Fujita
e854bb29cd a couple of typo fixes in doc section for LoanedMessage. (#2676)
* rephrase doc section of LoanedMessage Class.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
Co-authored-by: Christophe Bedard <bedard.christophe@gmail.com>
2024-11-19 07:14:45 -05:00
Christophe Bedard
88ebea94e9 Make sure callback_end tracepoint is triggered in AnyServiceCallback (#2670)
Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
2024-11-11 13:39:38 -08:00
YR
1e6767ac13 Fix documentation typo in server_goal_handle.hpp (#2669)
Signed-off-by: Yurii Rovinskyi <yurii.rovinskyi.19@pnu.edu.ua>
2024-11-10 07:54:41 -08:00
Barry Xu
37e3688026 Correct the incorrect comments in generic_client.hpp (#2662)
Signed-off-by: Barry Xu <barry.xu@sony.com>
2024-11-05 08:07:02 -05:00
Romain DESILLE
9b654942f9 Fix NodeOptions assignment operator (#2656)
* Fix NodeOptions assignment operator

Also copy the enable_logger_service_ member during the assignment operation

* Add more checks for NodeOptions copy test

* Set non default values by avoiding the copy-assignement

Signed-off-by: Romain DESILLE <r.desille@gmail.com>
Co-authored-by: Christophe Bedard <bedard.christophe@gmail.com>
2024-10-30 07:45:19 -04:00
Tomoya Fujita
f12e3c69dc set QoS History KEEP_ALL explicitly for statistics publisher. (#2650)
* set QoS History KEEP_ALL explicitly for statistics publisher.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* test_subscription_options adjustment.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-10-19 14:21:20 -07:00
Chris Lalancette
bcc14755f9 Fix test_intra_process_manager.cpp with rmw_zenoh_cpp (#2653)
* Cleanup of test_intra_process_manager.cpp

In particular, make every pub and sub have to
pass in both a topic name and a QoS when they
are constructing mock pubs and subs for the
intra-process manager test.  This just makes it
easier to tell whether the pubs and subs should be
matched or not.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>

* Make sure to check QoS compatibility in the intra_process_manager tests.

It turns out that the intra_process_manager will attempt to match
QoS between publishers and subscriptions as they are added to the IPM.
This is exactly correct, but the tests were not following the same
pattern.

Thus, when running these tests under Zenoh, the tests would fail
because more things would match than the tests were expecting.
Update the test to take the differences in QoS into account,
which fixes the test under rmw_zenoh_cpp (and keeps it working
for the existing DDS RMWs).

Signed-off-by: Chris Lalancette <clalancette@gmail.com>

* Added feedback

Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>

---------

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
Co-authored-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2024-10-19 00:55:25 +02:00
Alejandro Hernández Cordero
4567b6ec80 Fixed test_events_executors in zenoh (#2643)
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2024-10-17 18:20:47 +02:00
Tomoya Fujita
0be8aa013e rmw_fastrtps supports service event gid uniqueness test. (#2638)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-10-14 15:24:42 -04:00
Tomoya Fujita
41d3a27437 print warning if event callback is not supported instead of passing exception. (#2648)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-10-09 15:22:46 +02:00
Christophe Bedard
c50f0c9c3d Fix error message in rclcpp_lifecycle::State::reset() (#2647)
The function that may not complete successfully is
`rcl_lifecycle_state_fini()`, not `rcl_lifecycle_transition_fini()`.

Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
2024-10-09 12:26:26 +02:00
Barry Xu
f8aea8cc51 Implement callback support of async_send_request for service generic client (#2614)
Signed-off-by: Barry Xu <barry.xu@sony.com>
2024-10-04 12:12:00 +02:00
Chris Lalancette
16290fb352 29.0.0 2024-10-03 16:06:52 +00:00
Chris Lalancette
e133cc65f6 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-10-03 16:06:42 +00:00
Chris Lalancette
50a1e50133 Increase the timeout for the cppcheck on rclcpp_action. (#2640)
The default is 300 seconds, but on Windows this is taking
between 250 and 300 seconds (I'm seeing it timeout sometimes).
Up the timeout to 600 seconds, which should be more than enough.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-10-03 10:33:15 -04:00
Alejandro Hernández Cordero
1a0092a65b Fixed test qos rmw zenoh (#2639)
* Fixed test qos rmw zenoh

Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>

* Update rclcpp/test/rclcpp/test_qos.cpp

Co-authored-by: Yadu <yadunund@openrobotics.org>
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>

---------

Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
Co-authored-by: Yadu <yadunund@openrobotics.org>
2024-10-02 10:59:48 -07:00
Tomoya Fujita
2813045a96 verify client gid uniqueness for a single service event. (#2636)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-10-01 10:15:58 -04:00
Alejandro Hernández Cordero
51dfdc3708 Skip some tests in test_qos_event and run others with event types supported by rmw_zenoh (#2626)
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
Signed-off-by: Yadunund <yadunund@intrinsic.ai>
Co-authored-by: Yadunund <yadunund@intrinsic.ai>
2024-09-30 10:03:51 +02:00
Alejandro Hernández Cordero
1f408e3b19 Shutdown the context before context's destructor is invoked in tests (#2633)
* zenoh: Shutdown the node properly in component tests

Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>

* Call rclcpp::shutdown when tearing down tests in rclcpp

Signed-off-by: Yadunund <yadunund@intrinsic.ai>

* Call rclcpp::shutdown when tearing down tests in rclcpp_lifecycle

Signed-off-by: Yadunund <yadunund@intrinsic.ai>

* Ensure context is initialized for all tests in test_publisher

Signed-off-by: Yadunund <yadunund@intrinsic.ai>

* Added feedback

Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>

* make linters happy

Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>

---------

Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
Signed-off-by: Yadunund <yadunund@intrinsic.ai>
Co-authored-by: Yadunund <yadunund@intrinsic.ai>
2024-09-24 09:36:54 -07:00
Alejandro Hernández Cordero
63105cd8a6 Skip rmw zenoh content filtering tests (#2627)
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2024-09-23 11:19:04 -07:00
Alberto Soragna
a78d0cbd33 add smart pointer macros definitions to action server and client base classes (#2631)
Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2024-09-16 18:42:47 +02:00
Barry Xu
918363d081 Use InvalidServiceTypeError for unavailable service type in GenericClient (#2629)
Signed-off-by: Barry Xu <barry.xu@sony.com>
2024-09-16 08:53:48 -07:00
Tomoya Fujita
97c386ce40 LifecycleNode bugfix and add test cases (#2562)
* LifecycleNode base class resource needs to be reset via dtor.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* add debug notice that prints LifecycleNode is not shutdown in dtor.

  Currently it is user application responsibility to manage the all state control.
  See more details for https://github.com/ros2/rclcpp/issues/2520.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* add test cases to call shutdown from each primary state.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* address review comments.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-09-12 09:49:53 -07:00
Barry Xu
1a3dfaf45c Implement generic service (#2617)
* Implement generic service

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Add the required header files

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Fix compiling errors on Windows

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Fix compiling errors on Windows

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Fix compiling errors on Windows

Signed-off-by: Barry Xu <barry.xu@sony.com>

---------

Signed-off-by: Barry Xu <barry.xu@sony.com>
2024-09-12 09:04:59 -07:00
Alberto Soragna
f7056c0d86 fix events-executor warm-up bug and add unit-tests (#2591)
* add unit-test to verify that spin-all doesn't need warm-up

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* improve comment and add callback group test

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* move executor tests to a new file

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* do not require warm up iteration with events executor spin_some

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* add spin_some tests and cleanup

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* add missing include directives

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

---------

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2024-09-11 09:08:37 +02:00
Alberto Soragna
2f71d6e249 remove unnecessary gtest-skip in test_executors (#2600)
Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2024-09-06 14:18:03 +02:00
Barry Xu
e846f56224 Correct node name in service test code (#2615)
Signed-off-by: Barry Xu <barry.xu@sony.com>
2024-09-02 09:42:48 +02:00
Kang, Hsin-Yi
ee94bc63e4 Minor naming fixes for ParameterValue to_string() function (#2609)
More appropriate function argument naming.
Refer to: 
https://github.com/ros2/rclcpp/blob/rolling/rclcpp/src/rclcpp/parameter_value.cpp#L83

Signed-off-by: Kang, Hsin-Yi <f039281310@yahoo.com.tw>
2024-08-22 15:46:50 +02:00
Alejandro Hernández Cordero
b7c789328a Removed clang warnings (#2605)
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2024-08-22 08:45:51 +02:00
Chris Lalancette
4b1c125cac Fix a couple of issues in the documentation. (#2608)
These should make it render more nicely.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-08-21 17:58:34 -04:00
Alberto Soragna
dfaaf4739a deprecate the static single threaded executor (#2598)
* deprecate the static single threded executor

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* suppress deprecation warning for static executor and remove benchmark tests

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* fix uncrustify linter errors

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* fix windows deprecation warnings

i created an alias to give the deprecated executor a new name; this works when the class is directly used but it doesn't work in combination with templates (like std::make_shared<DeprecatedAlias>) because the compiler needs to resolved the type behind the alias triggering the warning

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* update test_reinitialized_timers.cpp to use the executor test utilities

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* do not use executor pointer

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

---------

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
Co-authored-by: Alberto Soragna <asoragna@irobot.com>
2024-08-19 20:13:21 -07:00
Christophe Bedard
e6b6faf152 Fix name of ParameterEventHandler class in doc (#2604)
Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
2024-08-18 09:29:52 -07:00
Christophe Bedard
f961ca7855 Fix typo in rclcpp_components benchmark_components (#2602)
Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
2024-08-12 09:39:49 -07:00
Tomoya Fujita
6da8363582 subscriber_statistics_collectors_ should be protected by mutex. (#2592)
* subscriber_statistics_collectors_ should be protected by mutex.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* reduce mutex lock scope.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-08-08 17:05:34 -07:00
Christophe Bedard
ab7cf878c2 Properly test get_service_names_and_types_by_node in rclcpp_lifecycle (#2599)
The current
`TestLifecycleServiceClient.get_service_names_and_types_by_node` test
was using `LifecycleServiceClient`, which is just a normal
`rclcpp::Node` with some `rclcpp::Client`s, to test
`NodeGraph::get_service_names_and_types_by_node()`. However,
`NodeGraph::get_service_names_and_types_by_node()` is for service
servers, not clients. The test just ended up checking the built-in
services of an `rclcpp::Node`, since it wasn't actually checking the
names of the services, and not checking the clients of the
`LifecycleServiceClient` or the built-in services of a
`rclcpp_lifecycle::LifecycleNode`. I believe this was probably not the
intention, since this is an `rclcpp_lifecycle` test.

Instead, use an actual `rclcpp_lifecycle::LifecycleNode` and check its
service servers by calling
`NodeGraph::get_service_names_and_types_by_node()` through
`LifecycleNode::get_service_names_and_types_by_node()`.

Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
2024-08-08 13:01:15 -07:00
Alexis Pojomovsky
496c45549b Fix bug in timers lifecycle for events executor (#2586)
* Remove expired timers before updating the collection

Signed-off-by: Alexis Pojomovsky <apojomovsky@ekumenlabs.com>

* Add regression test for reinitialized timers bug

Signed-off-by: Alexis Pojomovsky <apojomovsky@ekumenlabs.com>

* Add missing includes

Signed-off-by: Alexis Pojomovsky <apojomovsky@ekumenlabs.com>

* Relocate test under the executors directory

Signed-off-by: Alexis Pojomovsky <apojomovsky@ekumenlabs.com>

* Extend test to run with all supported executors

Signed-off-by: Alexis Pojomovsky <apojomovsky@ekumenlabs.com>

* Adjust comment in fix to make it more generic

Signed-off-by: Alexis Pojomovsky <apojomovsky@ekumenlabs.com>

* Apply ament clang format to test

Signed-off-by: Alexis Pojomovsky <apojomovsky@ekumenlabs.com>

* Fix uncrustify findings

Signed-off-by: Alexis Pojomovsky <apojomovsky@ekumenlabs.com>

---------

Signed-off-by: Alexis Pojomovsky <apojomovsky@ekumenlabs.com>
Co-authored-by: Alexis Pojomovsky <apojomovsky@ekumenlabs.com>
2024-08-07 18:15:08 -07:00
Alberto Soragna
2739327ee9 fix rclcpp/test/rclcpp/CMakeLists.txt to check for the correct targets existance (#2596)
Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2024-08-05 12:07:07 -07:00
Christophe Bedard
4e4f0cf43b Shut down context during init if logging config fails (#2594)
We already do this clean-up if some other tasks below fail.

Before:

  [ RUN      ] TestUtilities.test_context_init_shutdown_fails
  [ERROR] [1722555370.075637014] [rclcpp]: rcl context unexpectedly not shutdown during cleanup
  [WARN] [1722555370.077175569] [rclcpp]: logging was initialized more than once
  [       OK ] TestUtilities.test_context_init_shutdown_fails (3 ms)

After:

  [ RUN      ] TestUtilities.test_context_init_shutdown_fails
  [WARN] [1722555108.693207861] [rclcpp]: logging was initialized more than once
  [       OK ] TestUtilities.test_context_init_shutdown_fails (3 ms)

Also, remove an unnecessary line in `test_utilities`, and expect context
to not be valid if init fails.

Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
2024-08-05 08:12:33 -07:00
Chris Lalancette
c46896731c Make more of the Waitable API abstract (#2593)
* Make Waitable::{is_ready,add_to_wait_set,execute} abstract APIs.

I initially started looking at this because clang was complaining
that "all paths through this function will call itself".  And it
is correct; if an implementation does not override these methods,
and they are every called, they will go into an infinite loop
calling themselves.

However, while looking at it it seemed to me that these were really
part of the API that a concrete implementation of Waitable needed
to implement.  It is fine if an implementation doesn't want to do
anything (like the tests), but all of the "real" users in the codebase
override these.

Thus, remove the implementations here and make these pure virtual
functions that all subclasses must implement.

* Remove some more "empty" implementations.

In particular, these are implementations in the Waitable
class that only throw exceptions.  Rather than do this,
make these APIs pure virtual so all downstream classes
have to implement them.  All of the current users (except
for tests) do anyway, and it makes the API much cleaner.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-08-02 08:01:25 -04:00
Chris Lalancette
45adf6565f 28.3.3 2024-07-29 14:52:31 +00:00
Chris Lalancette
6f5c6f45d7 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-07-29 14:52:23 +00:00
Chris Lalancette
9b1e6c9d52 Only compile the tests once. (#2590)
Even when we want to run them on multiple RMWs, we can
do that by compiling once, then setting the environment
variable appropriately.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-07-26 12:37:34 -04:00
Alejandro Hernández Cordero
a4d7210b9c 28.3.2 2024-07-24 10:18:40 +02:00
Alejandro Hernández Cordero
fcc0261c49 Changelog
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2024-07-24 10:18:37 +02:00
Alejandro Hernández Cordero
b1fdb18f1e Updated rcpputils path API (#2579)
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2024-07-24 10:14:45 +02:00
Chris Lalancette
647bd65e28 Make the subscriber_triggered_to_receive_message test more reliable. (#2584)
* Make the subscriber_triggered_to_receive_message test more reliable.

In the current code, inside of the timer we create the subscription
and the publisher, publish immediately, and expect the subscription
to get it immediately.  But it may be the case that discovery
hasn't even happened between the publisher and the subscription
by the time the publish call happens.

To make this more reliable, create the subscription and publish *before*
we ever create and spin on the timer.  This at least gives 100
milliseconds for discovery to happen.  That may not be quite enough
to make this reliable on all platforms, but in my local testing this
helps a lot.  Prior to this change I can make this fail one out of 10
times, and after the change I've run 100 times with no failures.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-07-22 14:20:50 -04:00
Alberto Soragna
54b8f9cc97 Have the EventsExecutor use more common code (#2570)
* move notify waitable setup to its own function
* move mutex lock to retrieve_entity utility
* use entities_need_rebuild_ atomic bool in events-executors
* remove duplicated set_on_ready_callback for notify_waitable
* use mutex from base class rather than a new recursive mutex
* use current_collection_ member in events-executor
* delay adding notify waitable to collection
* postpone clearing the current collection
* commonize notify waitable and collection
* commonize add/remove node/cbg methods
* fix linter errors

---------

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2024-07-22 08:43:16 -05:00
Alejandro Hernández Cordero
bdf1f8f78a Removed deprecated methods and classes (#2575)
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2024-07-17 11:48:53 +02:00
Alberto Soragna
004db2b393 remove deprecated APIs from component_manager.hpp (#2585)
Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2024-07-16 15:48:59 +02:00
Chris Lalancette
304b51c3a1 Fix the lifecycle tests on RHEL-9. (#2583)
* Fix the lifecycle tests on RHEL-9.

The full explanation is in the comment, but basically since
RHEL doesn't support mocking_utils::inject_on_return, we have
to split out certain tests to make sure resources within a
process don't collide.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
Co-authored-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2024-07-12 09:44:50 -04:00
Barry Xu
069a001893 Release ownership of entities after spinning cancelled (#2556)
* Release ownership of entities after spinning cancelled

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Move release action to every exit point in different spin functions

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Move wait_result_.reset() before setting spinning to false

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Update test code

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Move test code to test_executors.cpp

Signed-off-by: Barry Xu <barry.xu@sony.com>

---------

Signed-off-by: Barry Xu <barry.xu@sony.com>
2024-07-10 11:06:43 +09:00
Chris Lalancette
c743c173e6 Split test_executors.cpp even further. (#2572)
That's because it is too large for Windows Debug to compile,
so split into smaller bits.

Even with this split, the file is too big; that's likely
because we are using TYPED_TEST here, which generates multiple
symbols per test case.  To deal with this, without further
breaking up the file, also add in the /bigobj flag when
compiling on Windows Debug.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-07-02 07:55:11 -04:00
Alberto Soragna
8de4b90512 avoid adding notify waitable twice to events-executor collection (#2564)
* avoid adding notify waitable twice to events-executor entities collection

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* remove redundant mutex lock

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

---------

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2024-06-29 14:55:28 -07:00
Chris Lalancette
8230d15ef7 28.3.1 2024-06-25 17:45:39 +00:00
Chris Lalancette
7d68b9096f Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-06-25 17:45:33 +00:00
Christophe Bedard
eeaa5222a1 Remove unnecessary msg includes in tests (#2566)
Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
2024-06-21 02:54:31 +02:00
Christophe Bedard
a13dc0f157 Fix copy-paste errors in function docs (#2565)
Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
2024-06-19 16:10:21 -07:00
Christophe Bedard
9f1de85079 Fix typo in function doc (#2563)
Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
2024-06-19 12:07:14 -07:00
Chris Lalancette
5149a095c1 28.3.0 2024-06-17 14:23:03 +00:00
Chris Lalancette
16795dd8bf Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-06-17 14:22:56 +00:00
Tomoya Fujita
f4923c6f43 revert call shutdown in LifecycleNode destructor (#2557)
* Revert "LifecycleNode shutdown on dtor only with valid context. (#2545)"

This reverts commit d8d83a0ee6.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* Revert "call shutdown in LifecycleNode dtor to avoid leaving the device in unknown state (2nd) (#2528)"

This reverts commit 3bc364a10b.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-06-11 07:41:09 -07:00
Alejandro Hernández Cordero
7c096888ca Add test creating two content filter topics with the same topic name (#2546) (#2549)
Signed-off-by: Mario-DL <mariodominguez@eprosima.com>
Co-authored-by: Mario Domínguez López <116071334+Mario-DL@users.noreply.github.com>
2024-06-04 16:22:38 -07:00
Tomoya Fujita
d8d83a0ee6 LifecycleNode shutdown on dtor only with valid context. (#2545)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-05-30 14:57:17 -07:00
Tomoya Fujita
3bc364a10b call shutdown in LifecycleNode dtor to avoid leaving the device in unknown state (2nd) (#2528)
* Revert "Revert "call shutdown in LifecycleNode dtor to avoid leaving the device in un… (#2450)" (#2522)"

This reverts commit 42b0b5775b.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* lifecycle node dtor shutdown should be called only in primary state.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* adjust warning message if the node is still in transition state in dtor.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-05-29 09:40:49 -07:00
Tomoya Fujita
22df1d593a rclcpp::shutdown should not be called before LifecycleNode dtor. (#2527)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-05-23 17:53:35 -07:00
William Woodall
343b29b617 add impl pointer for ExecutorOptions (#2523)
* add impl pointer for ExecutorOptions

Signed-off-by: William Woodall <william@osrfoundation.org>
2024-05-09 16:32:44 -04:00
Chris Lalancette
42b0b5775b Revert "call shutdown in LifecycleNode dtor to avoid leaving the device in un… (#2450)" (#2522)
This reverts commit 04ea0bb002.
2024-05-09 07:34:04 -04:00
William Woodall
f7185dc129 Fixup Executor::spin_all() regression fix (#2517)
* test(Executors): Added tests for busy waiting

Checks if executors are busy waiting while they should block
in spin_some or spin_all.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* fix: Reworked spinAll test

This test was strange. It looked like, it assumed that spin_all did
not return instantly. Also it was racy, as the thread could terminate
instantly.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* fix(Executor): Fixed spin_all not returning instantly is no work was available

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* Update rclcpp/test/rclcpp/executors/test_executors.cpp

Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Signed-off-by: jmachowinski <jmachowinski@users.noreply.github.com>

* test(executors): Added test for busy waiting while calling spin

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* fix(executor): Reset wait_result on every call to spin_some_impl

Before, the method would not recollect available work in case of
spin_some, spin_all. This would lead to the method behaving differently
than to what the documentation states.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* restore previous test logic for now

Signed-off-by: William Woodall <william@osrfoundation.org>

* refactor spin_some_impl's logic and improve busy wait tests

Signed-off-by: William Woodall <william@osrfoundation.org>

* added some more comments about the implementation

Signed-off-by: William Woodall <william@osrfoundation.org>

---------

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Signed-off-by: jmachowinski <jmachowinski@users.noreply.github.com>
Signed-off-by: William Woodall <william@osrfoundation.org>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: jmachowinski <jmachowinski@users.noreply.github.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-05-02 14:06:10 -07:00
Scott K Logan
5f912eb58e Add 'mimick' label to tests which use Mimick (#2516)
Signed-off-by: Scott K Logan <logans@cottsay.net>
2024-04-29 16:09:43 -05:00
Marco A. Gutierrez
2cd8900dd2 28.2.0 2024-04-26 16:57:57 +00:00
Marco A. Gutierrez
cf6141330a Changelog.
Signed-off-by: Marco A. Gutierrez <marcogg@marcogg.com>
2024-04-26 16:57:52 +00:00
Sharmin Ramli
de666d2bf4 Check for negative time in rclcpp::Time(int64_t nanoseconds, ...) constructor (#2510)
Signed-off-by: Nursharmin Ramli <nursharminramli@gmail.com>
2024-04-23 22:47:56 +02:00
Barry Xu
55939613a0 Revise the description of service configure_introspection() (#2511)
Signed-off-by: Barry Xu <barry.xu@sony.com>
2024-04-23 13:29:46 +02:00
Chris Lalancette
3d58f0fb70 28.1.0 2024-04-16 17:16:42 +00:00
Chris Lalancette
3fd0831af2 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-04-16 17:16:35 +00:00
Chris Lalancette
d648a7c926 Remove references to index.ros.org. (#2504)
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-04-16 08:42:38 -07:00
William Woodall
6bb9407b90 Reduce overhead for inheriting from rclcpp::Executor when base functionality is not reused (#2506)
* feat(clock): Added function to interrupt sleep

This is useful in case a second thread needs to wake up another
thread, that is sleeping using a clock.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* feat: Added support for multi thread wait / shutdown

This adds support for multiple threads waiting on the same
clock, while an shutdown is invoked.

Signed-off-by: Janosch Machowinski <j.machowinski@cellumation.com>

* chore: Made Executor fully overloadable

This commit makes every public funciton virtual, and adds virtual impl
function for the existing template functions.

The goal of this commit is to be able to fully control the everything from
a derived class.

Signed-off-by: Janosch Machowinski <j.machowinski@cellumation.com>

* Update rclcpp/include/rclcpp/executor.hpp

Co-authored-by: William Woodall <wjwwood@gmail.com>
Signed-off-by: jmachowinski <jmachowinski@users.noreply.github.com>

* Update rclcpp/include/rclcpp/executor.hpp

Co-authored-by: William Woodall <wjwwood@gmail.com>
Signed-off-by: jmachowinski <jmachowinski@users.noreply.github.com>

* Update rclcpp/include/rclcpp/executor.hpp

Co-authored-by: William Woodall <wjwwood@gmail.com>
Signed-off-by: jmachowinski <jmachowinski@users.noreply.github.com>

* Update rclcpp/include/rclcpp/executor.hpp

Co-authored-by: William Woodall <wjwwood@gmail.com>
Signed-off-by: jmachowinski <jmachowinski@users.noreply.github.com>

* docs: added doc string for spin_until_future_complete_impl

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* made is_spinning not virtual

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* feat: Changed interface of spin_until_future_complete_impl

This change allows it to use a second thread to wait for
the future to become ready.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* doc fixup

Signed-off-by: William Woodall <william@osrfoundation.org>

* undo template->implicit conversion change

Signed-off-by: William Woodall <william@osrfoundation.org>

* style

Signed-off-by: William Woodall <william@osrfoundation.org>

---------

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Signed-off-by: Janosch Machowinski <j.machowinski@cellumation.com>
Signed-off-by: jmachowinski <jmachowinski@users.noreply.github.com>
Signed-off-by: William Woodall <william@osrfoundation.org>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: jmachowinski <jmachowinski@users.noreply.github.com>
2024-04-16 08:35:56 -07:00
Alejandro Hernández Cordero
535d56f690 28.0.1 2024-04-16 15:43:00 +02:00
Alejandro Hernández Cordero
1351737f34 Changelog
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2024-04-16 15:42:55 +02:00
jmachowinski
839348c601 Callback after cancel (#2281)
* feat(Client): Added function to stop callbacks of a goal handle

This function allows us to drop the handle in a locked context.
If we do not do this within a lock, there will be a race condition between
the deletion of the shared_ptr of the handle and the result / feedback
callbacks.

* fix: make Client goal handle recursive

This fixes deadlocks due to release of goal handles in callbacks etc.

* fix(ActionGoalClient): Fixed memory leak for nominal case

This fixes a memory leak due to a self reference in the ClientGoalHandle.
Note, this fix will only work, if the ClientGoalHandle ever receives
a result callback.

* doc: Updated documentation of rclcpp_action::Client::async_send_goal
* docs: Made the async_send_goal documentation more explicit

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2024-04-15 12:05:17 -05:00
William Woodall
90e451154c [wjwwood] Updated "Data race fixes" (#2500)
* Fix callback group logic in executor

Signed-off-by: Janosch Machowinski <j.machowinski@cellumation.com>

* fix: Fixed unnecessary copy of wait_set

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* fix(executor): Fixed race conditions with rebuild of wait_sets

Before this change, the rebuild of wait set would be triggered
after the wait set was waken up. With bad timing, this could
lead to the rebuild not happening with multi threaded executor.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* fix(Executor): Fixed lost of entities rebuild request


Signed-off-by: Janosch Machowinski <j.machowinski@cellumation.com>

* chore: Added assert for not set callback_group in execute_any_executable

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* Add test for cbg getting reset

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>
Co-authored-by: Janosch Machowinski <j.machowinski@nospam.org>

* chore: renamed test cases to snake_case

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* style

Signed-off-by: William Woodall <william@osrfoundation.org>

* fixup test to avoid polling and short timeouts

Signed-off-by: William Woodall <william@osrfoundation.org>

* fix: Use correct notify_waitable_ instance

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* fix(StaticSingleThreadedExecutor): Added missing special case handling for current_notify_waitable_

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

* fix(TestCallbackGroup): Fixed test after change to timers

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>

---------

Signed-off-by: Janosch Machowinski <j.machowinski@cellumation.com>
Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>
Signed-off-by: William Woodall <william@osrfoundation.org>
Co-authored-by: Janosch Machowinski <j.machowinski@cellumation.com>
Co-authored-by: Michael Carroll <mjcarroll@intrinsic.ai>
Co-authored-by: Janosch Machowinski <j.machowinski@nospam.org>
2024-04-12 14:57:15 -07:00
William Woodall
dec22a296f fixup var names to snake case (#2501)
Signed-off-by: William Woodall <william@osrfoundation.org>
2024-04-12 09:50:22 -05:00
jmachowinski
634cb873a3 Added optional TimerInfo to timer callback (#2343)
Signed-off-by: Alexis Tsogias <a.tsogias@cellumation.com>
Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Alexis Tsogias <a.tsogias@cellumation.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2024-04-12 07:28:59 -05:00
Chris Lalancette
ddc8a9c847 Fix uninitialized memory in test (#2498)
When I added in the tests for large messages, I made a mistake and reserved space in the strings, but didn't actually expand it.  Thus, we were writing into uninitialized memory.  Fix this by just using the correct constructor for string, which will allocate and initialize the memory properly.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-04-11 11:55:44 -04:00
William Woodall
dd81ef26a0 Remake of "fix: Fixed race condition in action server between is_ready and take" (#2495)
Some background information: is_ready, take_data and execute data
may be called from different threads in any order. The code in the old
state expected them to be called in series, without interruption.
This lead to multiple race conditions, as the state of the pimpl objects
was altered by the three functions in a non thread safe way.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Signed-off-by: William Woodall <william@osrfoundation.org>
Signed-off-by: Janosch Machowinski <j.machowinski@nospam.org>
Co-authored-by: Janosch Machowinski <j.machowinski@nospam.org>
2024-04-09 18:45:09 -05:00
William Woodall
bfa7efac46 Ensure waitables handle guard condition retriggering (#2483)
Signed-off-by: William Woodall <william@osrfoundation.org>
Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>
Co-authored-by: Michael Carroll <mjcarroll@intrinsic.ai>
2024-04-08 09:35:51 -05:00
Homalozoa X
63c2e2ef6f fix: init concatenated_vector with begin() & end() (#2492)
*. this commit will fix the warning [-Wstringop-overflow=] #2461

Signed-off-by: homalozoa <nx.tardis@gmail.com>
2024-04-08 15:17:46 +02:00
Tomoya Fujita
04ea0bb002 call shutdown in LifecycleNode dtor to avoid leaving the device in un… (#2450)
* call shutdown in LifecycleNode dtor to avoid leaving the device in unknown state.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* add test to verify LifecycleNode::shutdown is called on destructor.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-04-06 16:42:04 -07:00
Kotaro Yoshimoto
ea4c98c43f Use the same context for the specified node in rclcpp::spin functions (#2433)
* Use the same conext for the specified node in rclcpp::spin_xx functions

Signed-off-by: GitHub <noreply@github.com>

* Add test for spinning with non-default-context

Signed-off-by: Kotaro Yoshimoto <pythagora.yoshimoto@gmail.com>

* Format code

Signed-off-by: Kotaro Yoshimoto <pythagora.yoshimoto@gmail.com>

---------

Signed-off-by: GitHub <noreply@github.com>
Signed-off-by: Kotaro Yoshimoto <pythagora.yoshimoto@gmail.com>
2024-04-06 16:23:50 +01:00
Alejandro Hernández Cordero
fa596801c4 Disable compare-function-pointers in test_utilities (#2489)
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2024-04-05 19:29:20 +02:00
Tomoya Fujita
3cdb25934e address ambiguous auto variable. (#2481)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Signed-off-by: Steve Nogar <stephen.m.nogar.civ@army.mil>
2024-04-04 14:56:23 -07:00
Alejandro Hernández Cordero
9171835c35 Increase the cppcheck timeout to 1200 seconds (#2484)
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2024-04-04 19:50:12 +02:00
Alejandro Hernández Cordero
f7a7954ae7 Removed test_timers_manager clang warning (#2479)
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2024-04-04 16:04:54 +02:00
jmachowinski
f9c4894f96 Flaky timer test fix (#2469)
* fix(time_source): Fixed possible race condition

Signed-off-by: Janosch Machowinski <j.machowinski@nospam.org>

* fix(test_executors_time_cancel_behaviour): Fixed multiple race conditions

Signed-off-by: Janosch Machowinski <j.machowinski@nospam.org>

---------

Signed-off-by: Janosch Machowinski <j.machowinski@nospam.org>
Co-authored-by: Janosch Machowinski <j.machowinski@nospam.org>
2024-04-02 09:11:30 -07:00
h-suzuki-isp
f510db1529 Add tracepoint for generic publisher/subscriber (#2448)
Signed-off-by: h-suzuki <h-suzuki@isp.co.jp>
2024-04-01 10:07:45 -07:00
William Woodall
c5bc4b6528 update rclcpp::Waitable API to use references and const (#2467)
Signed-off-by: William Woodall <william@osrfoundation.org>
2024-03-29 10:47:15 -05:00
Michael Carroll
5632a09af2 Utilize rclcpp::WaitSet as part of the executors (#2142)
* Deprecate callback_group call taking context

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Add base executor objects that can be used by implementors

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Template common operations

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Address reviewer feedback:

* Add callback to EntitiesCollector constructor
* Make function to check automatically added callback groups take a list

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Lint

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Address reviewer feedback and fix templates

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Lint and docs

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Make executor own the notify waitable

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Add pending queue to collector, remove from waitable

Also change node's get_guard_condition to return shared_ptr

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Change interrupt guard condition to shared_ptr

Check if guard condition is valid before adding it to the waitable

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Lint and docs

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Utilize rclcpp::WaitSet as part of the executors

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Don't exchange atomic twice

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Fix add_node and add more tests

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Make get_notify_guard_condition follow API tick-tock

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Improve callback group tick-tocking

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Don't lock twice

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Address reviewer feedback

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Add thread safety annotations and make locks consistent

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* @wip

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Reset callback groups for multithreaded executor

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Avoid many small function calls when building executables

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Re-trigger guard condition if buffer has data

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Address reviewer feedback

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Trace points

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Remove tracepoints

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Reducing diff

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Reduce diff

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Uncrustify

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Restore tests

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Back to weak_ptr and reduce test time

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* reduce diff and lint

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Restore static single threaded tests that weren't working before

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Restore more tests

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Fix multithreaded test

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Fix assert

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Fix constructor test

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Change ready_executables signature back

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Don't enforce removing callback groups before nodes

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Remove the "add_valid_node" API

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Only notify if the trigger condition is valid

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Only trigger if valid and needed

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Fix spin_some/spin_all implementation

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Restore single threaded executor

Signed-off-by: Michael Carroll <michael@openrobotics.org>

* Picking ABI-incompatible executor changes

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Add PIMPL

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Additional waitset prune

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Fix bad merge

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Expand test timeout

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Introduce method to clear expired entities from a collection

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Make sure to call remove_expired_entities().

Signed-off-by: Chris Lalancette <clalancette@gmail.com>

* Prune queued work when callback group is removed

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Prune subscriptions from dynamic storage

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Styles fixes.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>

* Re-trigger guard conditions

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Condense to just use watiable.take_data

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Lint

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Address reviewer comments (nits)

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Lock mutex when copying

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Refactors to static single threaded based on reviewers

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* More small refactoring

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Lint

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Lint

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Add ready executable accessors to WaitResult

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Make use of accessors from wait_set

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Fix tests

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Fix more tests

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Tidy up single threaded executor implementation

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* Don't null out timer, rely on call

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>

* change how timers are checked from wait result in executors

Signed-off-by: William Woodall <william@osrfoundation.org>

* peak -> peek

Signed-off-by: William Woodall <william@osrfoundation.org>

* fix bug in next_waitable logic

Signed-off-by: William Woodall <william@osrfoundation.org>

* fix bug in StaticSTE that broke the add callback groups to executor tests

Signed-off-by: William Woodall <william@osrfoundation.org>

* style

Signed-off-by: William Woodall <william@osrfoundation.org>

---------

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>
Signed-off-by: Michael Carroll <michael@openrobotics.org>
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
Signed-off-by: William Woodall <william@osrfoundation.org>
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
Co-authored-by: William Woodall <william@osrfoundation.org>
2024-03-28 20:21:57 -07:00
Alberto Soragna
9d5aaf5bae fix flakiness in TestTimersManager unit-test (#2468)
the previous version of the test was relying on the assumption that a timer with 1ms period gets called at least 6 times if the main thread waits 15ms. this is true most of the times, but it's not guaranteed, especially when running the test on windows CI servers. the new version of the test makes no assumptions on how much time it takes for the timers manager to invoke the timers, but rather focuses on ensuring that they are called the right amount of times, which is what's important for the purpose of the test

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2024-03-28 08:23:32 -05:00
Marco A. Gutierrez
bedc547f42 28.0.0
Signed-off-by: Marco A. Gutierrez <marcogg@marcogg.com>
2024-03-28 08:53:51 +00:00
Marco A. Gutierrez
1e34abd4b5 Changelog.
Signed-off-by: Marco A. Gutierrez <marcogg@marcogg.com>
2024-03-28 08:53:31 +00:00
Tomoya Fujita
6c7764e968 Do not generate the exception when action service response timeout. (#2464)
* Do not generate the exception when action service response timeout.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* address review comment.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-03-27 09:43:54 -07:00
Alberto Soragna
42810ee3be fix spin_some_max_duration unit-test for events-executor (#2465)
Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2024-03-26 08:34:28 -05:00
William Woodall
b50f9ab418 refactor and improve the parameterized spin_some tests for executors (#2460)
* refactor and improve the spin_some parameterized tests for executors

Signed-off-by: William Woodall <william@osrfoundation.org>

* disable spin_some_max_duration for the StaticSingleThreadedExecutor and EventsExecutor

Signed-off-by: William Woodall <william@osrfoundation.org>

* fixup and clarify the docstring for Executor::spin_some()

Signed-off-by: William Woodall <william@osrfoundation.org>

* style

Signed-off-by: William Woodall <william@osrfoundation.org>

* review comments

Signed-off-by: William Woodall <william@osrfoundation.org>

---------

Signed-off-by: William Woodall <william@osrfoundation.org>
2024-03-22 12:07:30 -07:00
Tomoya Fujita
198c82ca15 enable simulation clock for timer canceling test. (#2458)
* enable simulation clock for timer canceling test.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* move MainExecutorTypes to test_executors_timer_cancel_behavior.cpp.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-03-21 00:10:15 -07:00
Tomoya Fujita
3e470d5ac2 Revert "relax the test simulation rate for timer canceling tests. (#2453)" (#2456)
This reverts commit 1c350d0d7f.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-03-20 12:37:56 -07:00
Tomoya Fujita
1c350d0d7f relax the test simulation rate for timer canceling tests. (#2453)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2024-03-18 13:37:26 -07:00
mauropasse
5e14a283b6 Modify rclcpp_action::GoalUUID hashing algorithm (#2441)
* Add unit tests for hashing rclcpp_action::GoalUUID's

* Use the FNV-1a hash algorithm for Goal UUID

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>
2024-03-06 08:45:58 -05:00
Chris Lalancette
51a4d2ea39 Fix TypeAdapted publishing with large messages. (#2443)
Mostly by ensuring we aren't attempting to store
large messages on the stack.  Also add in tests.
I verified that before these changes, the tests failed,
while after them they succeed.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-03-05 17:53:55 -05:00
Barry Xu
3df73f0e38 Implement generic client (#2358)
* Implement generic client

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Fix the incorrect parameter declaration

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Deleted copy constructor and assignment for FutureAndRequestId

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Update codes after rebase

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Address review comments

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Address review comments from iuhilnehc-ynos

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Correct an error in a description

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Fix window build errors

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Address review comments from William

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Add doc strings to create_generic_client

Signed-off-by: Barry Xu <barry.xu@sony.com>

---------

Signed-off-by: Barry Xu <barry.xu@sony.com>
2024-03-04 21:35:40 -08:00
Tim Clephas
b007204fd8 Rule of five: implement move operators (#2425)
Signed-off-by: Tim Clephas <tim.clephas@nobleo.nl>
2024-02-29 08:08:55 -05:00
Chris Lalancette
726f2039b5 Various cleanups to deal with uncrustify 0.78. (#2439)
These should also work with uncrustify 0.72.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-02-29 08:03:43 -05:00
Ruddick Lawrence
64f9aa158b Add EXECUTOR docs (#2440)
Signed-off-by: Ruddick Lawrence <679360+mrjogo@users.noreply.github.com>
2024-02-29 08:01:16 -05:00
Chris Lalancette
e10728cde9 Remove the set_deprecated signatures in any_subscription_callback. (#2431)
These have been deprecated since April 2021, so it is safe
to remove them now.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-02-22 21:57:29 -05:00
Jonas Otto
1981e1f12a fix doxygen syntax for NodeInterfaces (#2428)
Signed-off-by: Jonas Otto <jonas@jonasotto.com>
2024-02-20 10:09:44 -08:00
Chris Lalancette
10252e9f66 Set hints to find the python version we actually want. (#2426)
The comment in the commit explains the reasoning behind it.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-02-16 14:43:02 -05:00
Christophe Bedard
b4571076a6 Update quality declaration documents (#2427)
Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
2024-02-16 08:30:53 -05:00
Adam Aposhian
091f29fcd3 crash on no class found (#2415)
* crash on no class found

* error on no class found instead of no callback groups

Signed-off-by: Adam Aposhian <adam.aposhian@fireflyautomatix.com>
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
2024-02-13 17:18:15 -05:00
HuaTsai
38bcda4b76 feat: add/minus for msg::Time and rclcpp::Duration (#2419)
* feat: add/minus for msg::Time and rclcpp::Duration

Signed-off-by: HuaTsai <huatsai.eed07g@nctu.edu.tw>
2024-02-13 14:08:16 -05:00
Chris Lalancette
c500695e21 27.0.0 2024-02-07 13:51:05 +00:00
Chris Lalancette
e1f84baa11 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-02-07 13:50:55 +00:00
Chris Lalancette
c10764f432 Split test_executors up into smaller chunks. (#2421)
The original reason is that on Windows Debug, we were
failing to compile because the compilation unit was
too large.  But also this file was way too large (1200
lines), so it makes sense to split it up.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-02-01 12:05:38 -05:00
Matt Condino
99f0fc938b [events executor] - Fix Behavior with Timer Cancel (#2375)
* fix

Signed-off-by: Matt Condino <mwcondino@gmail.com>

* add timer cancel tests

Signed-off-by: Matt Condino <mwcondino@gmail.com>

* cleanup header include

Signed-off-by: Matt Condino <mwcondino@gmail.com>

* reverting change to timer_greater function

Signed-off-by: Gus Brigantino <gusbrig97@gmail.com>

* use std::optional, and handle edgecase of 1 cancelled timer

Signed-off-by: Matt Condino <mwcondino@gmail.com>

* clean up run_timers func

Signed-off-by: Gus Brigantino <gusbrig97@gmail.com>

* some fixes and added tests for cancel then reset of timers.

Signed-off-by: Matt Condino <mwcondino@gmail.com>

* refactor and clean up. remove cancelled timer tracking.

Signed-off-by: Matt Condino <mwcondino@gmail.com>

* remove unused method for size()

Signed-off-by: Matt Condino <mwcondino@gmail.com>

* linting

Signed-off-by: Matt Condino <mwcondino@gmail.com>

* relax timing constraints in tests

Signed-off-by: Matt Condino <mwcondino@gmail.com>

* further relax timing constraints to ensure windows tests are not flaky.

Signed-off-by: Matt Condino <mwcondino@gmail.com>

* use sim clock for tests, pub clock at .25 realtime rate.

Signed-off-by: Matt Condino <mwcondino@gmail.com>

---------

Signed-off-by: Matt Condino <mwcondino@gmail.com>
Signed-off-by: Gus Brigantino <gusbrig97@gmail.com>
Co-authored-by: Gus Brigantino <gusbrig97@gmail.com>
2024-01-30 06:16:37 -08:00
Alejandro Hernández Cordero
265f5ec297 Removed deprecated header (#2413)
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2024-01-26 09:44:36 +01:00
Chris Lalancette
a29f58edcb Make sure to mark RingBuffer methods as 'override'. (#2410)
This gets rid of a warning when building under clang.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-01-24 18:51:25 -05:00
Chris Lalancette
676897df9d 26.0.0 2024-01-24 14:08:12 +00:00
Chris Lalancette
6602fcf7bc Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-01-24 14:08:05 +00:00
Chris Lalancette
a5221336f6 Increase the cppcheck timeout to 600 seconds. (#2409)
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-01-18 16:40:13 -05:00
Jeffery Hsu
7901bb9da4 Add transient local durability support to publisher and subscriptions when using intra-process communication (#2303)
* Add intra process transient local durability support to publisher and subscription

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>

* Remove durability_is_transient_local_ from publisher_base
Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>

* Design changes that move most transient local publish functionalities out of
intra process manager into intra process manager

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>

* Move transient local publish to a separate function

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>

* Remove publisher buffer weak ptr from intra process manager when it associated publisher is removed.

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>

* Remove incorrectly placed RCLCPP_PUBLIC

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>

* Add missing RCLCPP_PUBLIC

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>

* Expand RingBufferImplementation beyond shared_ptr and unique_ptr

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>

* Comment and format fix

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>

---------

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>
2024-01-18 08:39:59 -08:00
Chris Lalancette
6f6b5f2e36 Stop storing the context in the guard condition. (#2400)
* Stop storing the context in the guard condition.

This was creating a circular reference between GuardCondition
and Context, so that Context would never be cleaned up.
Since we never really need the GuardCondition to know
about its own Context, remove that part of the circular
reference.

While we are in here, we also change the get_context()
lambda to a straight weak_ptr; there is no reason for the
indirection since the context for the guard condition
cannot change at runtime.

We also remove the deprecated version of the
get_notify_guard_condition().  That's because there is
no way to properly implement it in the new scheme, and
it seems to be unused outside of rclcpp.

Finally, we add in a test that guarantees the use_count
is what we expect when inside and leaving a scope, ensuring
that contexts will properly be destroyed.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2024-01-08 08:23:33 -05:00
Jorge Perez
126d517193 Increase timeout for rclcpp_lifecycle to 360 (#2395)
* Increase timeout for rclcpp_lifecycle to 360

Signed-off-by: Jorge Perez <jjperez@ekumenlabs.com>
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
2024-01-03 08:17:47 -05:00
Chris Lalancette
5d2b32b5c3 25.0.0 2023-12-26 17:17:23 +00:00
Chris Lalancette
21f8a22311 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-12-26 17:17:15 +00:00
DensoADAS
2bb1dc2c71 Updated GenericSubscription to AnySubscriptionCallback (#1928)
* added rclcpp::SerializedMessage support for AnySubscriptionCallback

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>
Signed-off-by: Joshua Hampp <j.hampp@eu.denso.com>

* using AnySubscription callback for generic subscriptiion

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>
Signed-off-by: Joshua Hampp <j.hampp@eu.denso.com>

* updated tests

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>
Signed-off-by: Joshua Hampp <j.hampp@eu.denso.com>

* Remove comment

Signed-off-by: Joshua Hampp <j.hampp@eu.denso.com>

---------

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>
Signed-off-by: Joshua Hampp <j.hampp@eu.denso.com>
Co-authored-by: Joshua Hampp <j.hampp@denso-adas.de>
Co-authored-by: Jacob Perron <jacob@openrobotics.org>
2023-12-19 08:35:13 -08:00
Chen Lihui
d9b2744057 make type support helper supported for service (#2209)
* make type support helper supported for service and action as well

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* not to use template and only add the necessary service type currently

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update comment

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* add deprecated cycle for `get_typesupport_handle`

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

---------

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2023-12-11 17:33:28 -08:00
Lucas Wendland
a19ad2134b Adding QoS to subscription options (#2323)
* Adding QoS to subscription options

Signed-off-by: CursedRock17 <mtglucas1@gmail.com>
2023-12-01 10:01:27 -05:00
Chris Lalancette
26f6efa840 Switch to target_link_libraries. (#2374)
That way we can hide more of the implementation by using
the PRIVATE keyword.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-11-27 16:39:20 -05:00
Daisuke Nishimatsu
d08d9cf5ff feat(rclcpp_components): support events executor in node main template (#2366)
Signed-off-by: wep21 <daisuke.nishimatsu1021@gmail.com>
2023-11-17 08:20:30 -05:00
Chen Lihui
2446fd000b aligh with rcl that a rosout publisher of a node might not exist (#2357)
* aligh with rcl

* keep same behavior with rclpy

1. to not throw exception durning rcl_logging_rosout_remove_sublogger
2. reset error message for RCL_RET_NOT_FOUND

* test for a node with rosout disabled

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2023-11-15 10:44:25 -05:00
mauropasse
411dbe8212 Fix data race in EventHandlerBase (#2349)
Both the EventHandler and its associated pubs/subs share
the same underlying rmw event listener.
When a pub/sub is destroyed, the listener is destroyed.
There is a data race when the ~EventHandlerBase wants
to access the listener after it has been destroyed.

The EventHandler stores a shared_ptr of its associated pub/sub.
But since we were clearing the listener event callbacks on the
base class destructor ~EventHandlerBase, the pub/sub was
already destroyed, which means the rmw event listener was also
destroyed, thus causing a segfault when trying to obtain it
to clear the callbacks.

Clearing the callbacks on ~EventHandler instead of
~EventHandlerBase avoids the race, since the pub/sub are still valid.

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>
2023-11-13 21:24:07 -05:00
Chris Lalancette
de841d9c8b Support users holding onto shared pointers in the message memory pool (#2336)
* Support users holding onto shared pointers in the message memory pool

Before this commit, the MessageMemoryPool would actually
reuse messages in the pool, even if the user had taken
additional shared_ptr copies.

This commit fixes things so that we properly handle that situation.  In particular, 
we allocate memory during class initialization, and delete
it during destruction.  We then run the constructor when
we hand the pointer out, and the destructor (only) when
we return it to the pool.  This keeps things consistent.
We also add in locks, since in a multi-threaded scenario we need
to protect against multiple threads accessing the pool
at the same time.

With this in place, things work as expected when users hold
shared_ptr copies.  We also add in a test for this situation.

One note about performance: this update preserves the
"no-allocations-at-runtime" aspect of the MessagePool.  However,
there are some tradeoffs with CPU time here, particularly with
very large message pools.  This could probably be optimized
further to do less work when trying to add items back to the
free_list, but I view that as a further enhancement.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-11-13 15:32:42 -05:00
M. Fatih Cırıt
9c098e544e fix(rclcpp_components): increase the service queue sizes in component_container (#2363)
* fix(rclcpp_components): increase the service queue sizes in component_container

Signed-off-by: M. Fatih Cırıt <mfc@leodrive.ai>
2023-11-09 15:09:18 -05:00
Chris Lalancette
0f331f90a9 24.0.0 2023-11-06 17:36:49 +00:00
Chris Lalancette
620fcf1e05 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-11-06 17:36:40 +00:00
Zard-C
d407a5e331 fix (signal_handler.hpp): spelling (#2356)
Signed-off-by: Zard-C <patrick.zhang5233@gmail.com>
2023-11-05 14:28:17 -05:00
Chris Lalancette
7f411371b3 Updates to not use std::move in some places. (#2353)
gcc 13.1.1 complains that these uses inhibit copy elision.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-11-05 14:27:40 -05:00
Tomoya Fujita
76e2b2677b rclcpp::Time::max() clock type support. (#2352)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-11-04 09:08:11 -07:00
Lucas Wendland
5049c45f85 Serialized Messages with Topic Statistics (#2274)
Signed-off-by: CursedRock17 <mtglucas1@gmail.com>
2023-11-03 15:06:25 -07:00
Michael Carroll
4691063a61 Add a custom deleter when constructing rcl_service_t (#2351)
* Add a custom deleter when constructing rcl_service_t

In the type description service construction, we were previously passing
the shared_ptr to the rcl_service_t with the assumption that
rclcpp::Service would do the clean up.  This was an incorrect
assumption, and so I have added a custom deleter to fini the service and
delete when the shared_ptr is cleaned up.

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>
2023-11-03 08:59:06 -04:00
Chris Lalancette
f294488e17 Disable the loaned messages inside the executor. (#2335)
* Disable the loaned messages inside the executor.

They are currently unsafe to use; see the comment in the
commit for more information.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-11-02 18:29:12 -04:00
Michael Orlov
8a02e3934c Use message_info in SubscriptionTopicStatistics instead of typed message (#2337)
* Use message_info in SubscriptionTopicStatistics instead of typed message

- Untemplatize the rclcpp::topic_statistics::SubscriptionTopicStatistics
class. Now we will be using message_info instead of typed deserialized
messages in the handle_message callbacks.

* Fix test_receive_stats_include_window_reset by using publisher emulator

- Emulate publishing messages by directly calling
rclcpp::Subscription::handle_message(msg_shared_ptr, message_info) and
settling up needed message_info.source_timestamp

Signed-off-by: Michael Orlov <michael.orlov@apex.ai>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-11-02 13:26:33 -04:00
Jiaqi Li
fff009a751 Add missing 'enable_rosout' comments (#2345)
Signed-off-by: Jiaqi Li <ljq0831@qq.com>
2023-10-31 00:21:28 -07:00
Michael Carroll
2204e44305 Adjust rclcpp usage of type description service (#2344)
Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>
2023-10-30 19:24:24 +00:00
Tomoya Fujita
fcbe64cff4 address rate related flaky tests. (#2329)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-10-26 00:08:18 -07:00
Chris Lalancette
c366e531fa Fixes pointed out by the clang analyzer. (#2339)
1. Remove the default Logger copy constructor without copy
assignment (rule of three -> rule of zero).
2. Remove an unnecessary capture in a lambda.
3. Mark a variable unused.
4. Mark a method as override.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-10-23 11:10:18 -05:00
Alexey Merzlyakov
5ffc963e1a Remove useless ROSRate class (#2326)
Signed-off-by: Alexey Merzlyakov <alexey.merzlyakov@samsung.com>
2023-10-16 09:38:38 -04:00
Chris Lalancette
7f7ffcf6ed Fix rclcpp_lifecycle inclusion on Windows. (#2331)
The comment in the commit explains this clearly, but
on Windows ERROR is a macro.  The reuse of it, even
as an enum, causes compilation errors on downstream
users.  Push the macro and undefine it so downstream
consumers can freely include it.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-10-10 13:25:55 -04:00
Chris Lalancette
13abc1beed 23.2.0 2023-10-09 15:31:54 +00:00
Chris Lalancette
e77c1fe550 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-10-09 15:31:47 +00:00
Minju, Lee
00b9d0a018 add clients & services count (#2072)
* add clients & services count

* add count clients,services tests

Signed-off-by: leeminju531 <dlalswn531@naver.com>
2023-10-09 10:36:00 -04:00
Tomoya Fujita
77c7aaf917 remove invalid sized allocation test for SerializedMessage. (#2330)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-10-06 15:15:34 -07:00
Steve Macenski
9019a8d9b7 Adding API to copy all parameters from one node to another (#2304)
Signed-off-by: stevemacenski <stevenmacenski@gmail.com>
2023-10-05 13:00:16 -07:00
Chris Lalancette
0644f220a2 23.1.0 2023-10-04 13:09:05 +00:00
Chris Lalancette
32438a6a67 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-10-04 13:08:56 +00:00
Ignacio Vizzo
d6bd8baac5 Add missing header required by the rclcpp::NodeOptions type (#2324)
Signed-off-by: Ignacio Vizzo <ignacio@dexory.com>
2023-10-04 08:18:21 -04:00
Chris Lalancette
623c3eb874 Add locking to protect the TimeSource::NodeState::node_base_ (#2320)
We need this because it is possible for one thread to
be handling the on_parameter_event callback while another
one is detaching the node.  This lock will protect that
from happening.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-10-03 14:16:49 -04:00
Tully Foote
7c1143dc15 Update SignalHandler get_global_signal_handler to avoid complex types in static memory (#2316)
* Update SignalHandler get_global_signal_handler to avoid complex types in static memory

This was flagged by msan as a problem.

There's a description of why this is a potential problem here: https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables

Signed-off-by: Tully Foote <tullyfoote@intrinsic.ai>
Co-authored-by: William Woodall <william+github@osrfoundation.org>
2023-09-29 16:13:43 -07:00
Lucas Wendland
9ff864c6ae Removing Old Connext Tests (#2313)
* Removing Old Connext Tests

Signed-off-by: CursedRock17 <mtglucas1@gmail.com>
2023-09-28 08:29:47 -04:00
Lucas Wendland
13182b5aad Documentation for list_parameters (#2315)
* list_parameters documentation

Signed-off-by: CursedRock17 <mtglucas1@gmail.com>
2023-09-27 17:14:53 -04:00
Tomoya Fujita
9284d7cefa Decouple rosout publisher init from node init. (#2174)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-09-21 18:44:13 -07:00
Minju, Lee
c42745c5ba fix the depth to relative in list_parameters (#2300)
* fix the depth to relative in list_parameters

Signed-off-by: leeminju531 <dlalswn531@naver.com>
2023-09-18 17:13:11 -04:00
Chris Lalancette
ea31f94eb4 23.0.0 2023-09-08 20:47:00 +00:00
Chris Lalancette
f496291e81 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-09-08 20:46:51 +00:00
Chris Lalancette
dd6fad6d42 Fix the return type of Rate::period. (#2301)
In a recent commit (bc435776a2),
we reworked how the Rate class worked so it could be
used with ROS time as well.  Unfortunately, we also
accidentally broke the API of it by changing the return
type of Rate::period to a Duration instead of a
std::chrono::nanoseconds .  Put this back to a std::chrono::nanoseconds;
if we want to change it to a Duration, we'll have to
add a new method and deprecate this one.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-09-08 16:40:09 -04:00
Christophe Bedard
38734d769a Update API docs links in package READMEs (#2302)
Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
2023-09-08 13:59:15 -04:00
jmachowinski
e103b8d37e fix(ClientGoalHandle): Made mutex recursive to prevent deadlocks (#2267)
* fix(ClientGoalHandle): Made mutex recursive to prevent deadlocks

This prevents deadlocks in cases, were e.g. get_status() would
be called on the handle in a callback of the handle.

* test(rclcpp_action): Added test for deadlocks during access of a goal handle

This test checks, if the code deadlocks, if methods on the goal handle are
called from the callbacks.

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-09-07 17:37:35 -04:00
Chris Lalancette
253d395d4e Cleanup flaky timers_manager tests. (#2299)
* Cleanup flaky timers_manager tests.

The timers_manager tests were relying too heavily on
specific timings; this caused them to be flaky on the
buildfarm, particularly on Windows.

Here, we increase the timeouts, and remove one test which
just relies too heavily on specific timeouts.  This should
make this test much less flaky on the buildfarm.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-09-07 15:17:16 -04:00
Chris Lalancette
d5e5141b3d 22.2.0 2023-09-07 14:59:44 +00:00
Chris Lalancette
a0148dfd5d Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-09-07 14:59:26 +00:00
Chen Lihui
5e152d77d8 Topic correct typeadapter deduction (#2294)
* fix TypeAdapter deduction

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2023-09-06 10:24:51 -04:00
AiVerisimilitude
fa732b9ee8 Fix C++20 allocator construct deprecation (#2292)
Signed-off-by: Guilherme Rodrigues <guilherme.rodrigues@ait.ac.at>
2023-09-01 17:17:00 -07:00
Alexey Merzlyakov
bc435776a2 Make Rate to select the clock to work with (#2123)
* Make Rate to select the clock to work with
Add ROSRate respective with ROS time

* Make GenericRate class to be deprecated

* Adjust test cases for new rates

is_steady() to be deprecated

Signed-off-by: Alexey Merzlyakov <alexey.merzlyakov@samsung.com>
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
2023-08-31 15:50:40 -04:00
Jiaqi Li
43cf0be15c Correct the position of a comment. (#2290)
Signed-off-by: Jiaqi Li <ljq0831@qq.com>
2023-08-29 13:22:51 -04:00
Chris Lalancette
fd58bddb05 Remove unnecessary lambda captures in the tests. (#2289)
* Remove unnecessary lambda captures in the tests.

This was pointed out by compiling with clang.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-08-28 14:17:27 -04:00
Tomoya Fujita
e7f06398db add logger level service to lifecycle node. (#2277)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-08-26 11:38:52 -07:00
Chris Lalancette
ba175922d3 Add rcl_logging_interface as an explicit dependency. (#2284)
It is depended on by rclcpp/src/rclcpp/logger.cpp, but
the dependency was not explicitly declared (it was
being inherited from rcl, I believe).  Fix that here.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-08-23 19:43:54 -04:00
Chris Lalancette
77db1ed25b Revamp list_parameters to be more efficient and easier to read. (#2282)
1. Use constref for the loop variable.
2. Do more work outside of the loop.
3. Skip doing unnecessary work where we can inside the loop.

With this in place, I measured about a 7% performance
improvement over the previous implementation.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-08-23 08:15:44 -04:00
Chris Lalancette
403f305b15 Fix a typo in a comment. (#2283)
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-08-22 15:22:01 -07:00
Tomoya Fujita
fd229d72ff doc fix: call canceled only after goal state is in canceling. (#2266)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-08-21 16:04:49 -04:00
Chris Lalancette
89f0afe9bc 22.1.0 2023-08-21 14:52:05 +00:00
Chris Lalancette
a4db4c57a6 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-08-21 14:51:57 +00:00
Tomoya Fujita
fbe8f28cd1 Do not crash Executor when send_response fails due to client failure. (#2276)
* Do not crash Executor when send_response fails due to client failure.

Related to https://github.com/ros2/ros2/issues/1253

It is not sane that a faulty client can crash our service Executor, as
discussed in the referred issue, if the client is not setup properly,
send_response may return RCL_RET_TIMEOUT, we should not throw an error
in this case.

Signed-off-by: Zang MingJie <zealot0630@gmail.com>

* Update rclcpp/include/rclcpp/service.hpp

Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Signed-off-by: Zang MingJie <zealot0630@gmail.com>

* address review comments.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Zang MingJie <zealot0630@gmail.com>
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Zang MingJie <zealot0630@gmail.com>
2023-08-18 09:15:04 -07:00
Lucas Wendland
65f0b70d4a Adding Custom Unknown Type Error (#2272)
Signed-off-by: CursedRock17 <mtglucas1@gmail.com>
Co-authored-by: Christophe Bedard <bedard.christophe@gmail.com>
2023-08-15 15:21:33 -07:00
Emerson Knapp
9b4b3da3d4 Add a pimpl inside rclcpp::Node for future distro backports (#2228)
* Add a pimpl inside rclcpp::Node for future distro backports

Signed-off-by: Emerson Knapp <emerson.b.knapp@gmail.com>
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
2023-08-10 08:31:05 -04:00
Chris Lalancette
cd0440f1a5 Remove an unused variable from the events executor tests. (#2270)
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-08-09 16:56:01 -04:00
Tony Najjar
a17d26b20a Add spin_all shortcut (#2246)
Signed-off-by: Tony Najjar <tony.najjar@logivations.com>
2023-08-08 16:38:13 -05:00
Lucas Wendland
e2965831d5 Adding Missing Group Exceptions (#2256)
* Adding Missing Group Exceptions

Signed-off-by: CursedRock17 <mtglucas1@gmail.com>
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-08-04 16:25:26 -04:00
Luca Della Vedova
ea29c142af Change associated clocks storage to unordered_set (#2257)
Signed-off-by: Luca Della Vedova <lucadv@intrinsic.ai>
2023-08-03 08:43:04 -04:00
Tomoya Fujita
5d6e5fa766 associated clocks should be protected by mutex. (#2255)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-08-01 22:43:02 -07:00
Christophe Bedard
22a954e1b0 Instrument loaned message publication code path (#2240)
Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
2023-07-21 11:26:42 -07:00
Chris Lalancette
c0d72c3ee0 Stop using constref signature of benchmark DoNotOptimize. (#2238)
* Stop using constref signature of benchmark DoNotOptimize.

Newer versions of google benchmark (1.8.2 in my case) warn
that the compiler may optimize away the DoNotOptimize calls
when using the constref version.  Get away from that here
by explicitly *not* calling the constref version, casting
where necessary.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-07-18 10:18:22 -04:00
Chris Lalancette
6e97990a32 22.0.0 2023-07-11 19:48:37 +00:00
Chris Lalancette
4ebc5f61d8 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-07-11 19:48:30 +00:00
Emerson Knapp
a7a9b78fee Implement get_node_type_descriptions_interface for lifecyclenode and add smoke test for it (#2237)
Signed-off-by: Emerson Knapp <emerson.b.knapp@gmail.com>
2023-07-11 08:41:53 -04:00
Chris Lalancette
945d254e32 Switch lifecycle to use the RCLCPP macros. (#2233)
This ensures that they'll go out to /rosout and the disk.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-07-10 15:59:35 -04:00
Emerson Knapp
deebbc3ad6 Add new node interface TypeDescriptionsInterface to provide GetTypeDescription service (#2224)
* TypeDescriptions interface with readonly param configuration

* Add parameter descriptor, to make read only

* example of spinning in thread for get_type_description service

* Add a basic test for the new interface

* Fix tests with new parameter

* Add comments about builtin parameters

Signed-off-by: Emerson Knapp <emerson.b.knapp@gmail.com>
Signed-off-by: William Woodall <william@osrfoundation.org>
2023-07-07 13:10:27 -04:00
Nathan Wiebe Neufeldt
588dba7a70 Move always_false_v to detail namespace (#2232)
Since this is a common idiom, especially under this name, we should
define the `always_false_v` template within a namespace to avoid
conflict with other libraries and user code. This could either be
`rclcpp::detail` if it's intended only for internal use or just `rclcpp`
if it's intended as a public helper. In this PR, I've initially chosen
the former.

Signed-off-by: Nathan Wiebe Neufeldt <nwiebeneufeldt@clearpath.ai>
2023-07-05 16:55:11 -04:00
Chris Lalancette
2e355e4849 Revamp the test_subscription.cpp tests. (#2227)
The original motiviation to do this was a crash during
teardown when using a newer version of gtest.  But while
I was in here, I did a small overall cleanup, including:

1.  Moving code closer to where it is actually used.
2.  Getting rid of unused 'using' statements.
3.  Adding in missing includes.
4.  Properly tearing down and recreating the rclcpp
    context during test teardown (this fixed the actual
    bug).
5.  Making class members private where possible.
6.  Renaming class methods to our usual conventions.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-06-26 12:59:56 -04:00
Tomoya Fujita
fe2e0e4c64 warning: comparison of integer expressions of different signedness (#2219)
https://github.com/ros2/rclcpp/pull/2167#issuecomment-1597197552

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-06-22 08:02:27 -07:00
Eloy Briceno
005f6aefe9 Modifies timers API to select autostart state (#2005)
* Modifies timers API to select autostart state

* Removes unnecessary variables

* Adds autostart documentation and expands some timer test

Signed-off-by: Voldivh <eloyabmfcv@gmail.com>
2023-06-21 10:47:14 -04:00
Christopher Wecht
3a64349aec Enable callback group tests for connextdds (#2182)
* Enable callback group tests for connextdds

* Enable executors and event executor tests for connextdds

* Enable qos events tests for connextdds

* Less flaky qos_event tests

Signed-off-by: Christopher Wecht <cwecht@mailbox.org>
2023-06-14 08:33:33 -04:00
Chris Lalancette
3530b0959c 21.3.0 2023-06-12 12:45:11 +00:00
Chris Lalancette
4d12bcbca0 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-06-12 12:45:00 +00:00
Chris Lalancette
1fff79089a Fix up misspellings of "receive". (#2208)
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-06-11 22:48:56 -07:00
Michael Carroll
b3518d12ca Remove flaky stressAddRemoveNode test (#2206)
Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>
2023-06-09 11:18:04 -05:00
Christophe Bedard
4efc05266b Use TRACETOOLS_ prefix for tracepoint-related macros (#2162)
Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
2023-06-08 12:38:49 -05:00
Chris Lalancette
dab9c8acdc 21.2.0 2023-06-07 13:28:18 +00:00
Chris Lalancette
867ad62da2 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-06-07 13:28:05 +00:00
Chen Lihui
f8072f2fa2 remove nolint since ament_cpplint updated for the c++17 header (#2198)
Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2023-05-22 21:22:13 -07:00
DensoADAS
fce021b149 Feature/available capacity of ipm (#2173)
* added available_capacity to get the lowest number of free capacity for intra-process communication for a publisher

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

* added unit tests for available_capacity

Signed-off-by: Joshua Hampp <j.hampp@eu.denso.com>
Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

* fixed typos in comments

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

* Updated warning

Co-authored-by: Alberto Soragna <alberto.soragna@gmail.com>
Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

* returning 0 if ipm is disabled in lowest_available_ipm_capacity

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

* return 0 if no subscribers are present in lowest_available_capacity

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

* updated unit test

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

* update unit test

Signed-off-by: Joshua Hampp <j.hampp@eu.denso.com>

* moved available_capacity to a lambda function to be able to handle subscriptions which went out of scope

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

* updated unit test to check subscriptions which went out of scope

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>

---------

Signed-off-by: Joshua Hampp <j.hampp@denso-adas.de>
Signed-off-by: Joshua Hampp <j.hampp@eu.denso.com>
Co-authored-by: Joshua Hampp <j.hampp@denso-adas.de>
Co-authored-by: Joshua Hampp <j.hampp@eu.denso.com>
Co-authored-by: Alberto Soragna <alberto.soragna@gmail.com>
2023-05-19 19:31:59 +01:00
Alberto Soragna
c4f57a7998 add mutex to protect events_executor current entity collection (#2187)
* add mutex to protect events_executor current entity collection and unit-test

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* be more precise with mutex locks; make stress test less stressfull

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* fix uncrustify error

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

---------

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2023-05-18 14:43:26 +01:00
mauropasse
d7fdb6184c Declare rclcpp callbacks before the rcl entities (#2024)
This is to ensure callbacks are destroyed last
on entities destruction, avoiding the gap in time
in which rmw entities hold a reference to a
destroyed function.

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>
Co-authored-by: Mauro Passerino <mpasserino@irobot.com>
2023-05-15 15:55:08 -04:00
Yadunund
58bcd3b822 21.1.1 2023-05-11 18:59:17 +08:00
Yadunund
26426adda9 Changelog
Signed-off-by: Yadunund <yadunund@openrobotics.org>
2023-05-11 18:58:48 +08:00
Alberto Soragna
6e1fea14e1 Fix race condition in events-executor (#2177)
The initial implementation of the events-executor contained a bug where the executor
would end up in an inconsistent state and stop processing interrupt/shutdown notifications.
Manually adding a node to the executor results in a) producing a notify waitable event
and b) refreshing the executor collections.
The inconsistent state would happen if the event was processed before the collections were
finished to be refreshed: the executor would pick up the event but be unable to process it.
This would leave the `notify_waitable_event_pushed_` flag to true, preventing additional
notify waitable events to be pushed.
The behavior is observable only under heavy load.

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2023-05-05 09:04:35 -05:00
Øystein Sture
86c77143c9 Add missing stdexcept include (#2186)
Signed-off-by: Øystein Sture <os@skarvtech.com>
2023-05-04 15:48:20 -04:00
Chris Lalancette
b812790ee3 Fix a format-security warning when building with clang (#2171)
In particular, you should never have a "bare" string in a
printf-like call; that could potentially access uninitialized
memory. Instead, make sure to format the string with %s.

Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-05-01 17:06:55 -04:00
methylDragon
6ca1023ef7 Fix delivered message kind (#2175)
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-05-01 16:56:29 -04:00
Yadunund
77ede02251 21.1.0 2023-04-27 16:53:54 +08:00
Chris Lalancette
a431256383 21.0.0 2023-04-18 15:35:47 +00:00
Chris Lalancette
9d2849cb0a Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-04-18 15:35:41 +00:00
Lei Liu
3610b68348 Add support for logging service. (#2122)
* Add support for logging service.

* Update to not modify interfaces and not change time_source

* Use unique_ptr for NodeBuiltinExecutorImpl

* Use user thread to run logger service

* Update code for lifecycle_node

Signed-off-by: Barry Xu <barry.xu@sony.com>
Signed-off-by: Lei Liu <Lei.Liu.AP@sony.com>
2023-04-18 11:30:00 -04:00
Michael Carroll
9c03a463c1 Picking ABI-incompatible executor changes (#2170)
* Picking ABI-incompatible executor changes

* Add PIMPL

Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>
2023-04-18 11:29:30 -04:00
Alberto Soragna
a7048e115d add events-executor and timers-manager in rclcpp (#2155)
* add events-executor and timers-manager in rclcpp

fix check for execute_timers_separate_thread; ignore on_ready_callback if asked to execute a timer;  reduce usage of void pointers

* have the executor notify waitable fiddle with guard condition callbacks only if necessary

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2023-04-17 14:33:58 -04:00
Michael Carroll
e3d9d819af Create common structures for executors to use (#2143)
* Deprecate callback_group call taking context

* Add base executor objects that can be used by implementors

* Template common operations

* Add callback to EntitiesCollector constructor
* Make function to check automatically added callback groups take a list

* Make executor own the notify waitable

* Add pending queue to collector, remove from waitable

Also change node's get_guard_condition to return shared_ptr

* Change interrupt guard condition to shared_ptr

Check if guard condition is valid before adding it to the waitable

* Make get_notify_guard_condition follow API tick-tock

* Improve callback group tick-tocking

* Add thread safety annotations and make locks consistent

* Remove the "add_valid_node" API

* Only notify if the trigger condition is valid

* Only trigger if valid and needed

Signed-off-by: Michael Carroll <michael@openrobotics.org>
2023-04-14 14:56:41 -04:00
Michael Babenko
6ffd54d61d Support publishing loaned messages in LifecyclePublisher (#2159)
* Support loaned messages in LifecyclePublisher

Signed-off-by: Michael Babenko <mbabenko@wayve.ai>
2023-04-14 13:15:03 -04:00
methylDragon
fd7a0dc219 Implement deliver message kind (#2168)
* Implement deliver message kind

Signed-off-by: methylDragon <methylDragon@gmail.com>

* Add examples to docstring

Signed-off-by: methylDragon <methylDragon@gmail.com>

---------

Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-13 20:08:27 -07:00
Chris Lalancette
eaf6edd6b2 20.0.0 2023-04-13 19:48:07 +00:00
Chris Lalancette
d478525778 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-04-13 19:48:00 +00:00
ymski
82a693e028 applied tracepoints for ring_buffer (#2091)
applied tracepoints for intra_publish
add tracepoints for linking buffer and subscription

Signed-off-by: Kodai Yamasaki <114902604+ymski@users.noreply.github.com>
2023-04-13 15:44:02 -04:00
methylDragon
b8173e28c6 Dynamic Subscription (REP-2011 Subset): Stubs for rclcpp (#2165)
* Implement subscription base changes

* Add stubbed out classes

Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-13 10:32:33 -04:00
Emerson Knapp
3088b536cc Add type_hash to cpp TopicEndpointInfo (#2137)
* Add type_hash to cpp TopicEndpointInfo

Signed-off-by: Emerson Knapp <emerson.b.knapp@gmail.com>
2023-04-12 08:57:57 -04:00
Michael Carroll
5f9695afb0 Trigger the intraprocess guard condition with data (#2164)
If the intraprocess buffer still has data after taking, re-trigger the
guard condition to ensure that the executor will continue to service it,
even if incoming publications stop.


Signed-off-by: Michael Carroll <michael@openrobotics.org>
2023-04-11 19:20:21 -05:00
Yadu
71a06985af Minor grammar fix (#2149)
Signed-off-by: Yadunund <yadunund@openrobotics.org>
2023-04-03 09:53:49 -07:00
Christopher Wecht
73d555b402 Fix unnecessary allocations in executor.cpp (#2135)
Signed-off-by: Christopher Wecht <cwecht@mailbox.org>
2023-04-03 09:01:39 -05:00
Tomoya Fujita
a5368e6fe4 add Logger::get_effective_level(). (#2141)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-03-29 21:50:17 -07:00
Emerson Knapp
20e9cd17f6 Remove deprecated header (#2139)
Signed-off-by: Emerson Knapp <emerson.b.knapp@gmail.com>
2023-03-26 08:45:36 -04:00
Barry Xu
cb08c79a0a Implement matched event (#2105)
Signed-off-by: Barry Xu <barry.xu@sony.com>
2023-03-22 08:36:47 -05:00
Tomoya Fujita
bff59925de extract the result response before the callback is issued. (#2132)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-03-21 14:11:48 -07:00
Tomoya Fujita
1a796b5515 use allocator via init_options argument. (#2129)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-03-17 12:35:34 -07:00
Chris Lalancette
cbd48c0eb4 Fixes to silence some clang warnings. (#2127)
This does 2 separate things:

* Adds (void)unused_variable things where needed.
* Stops doing some checks on moved-from items in tests.

With this in place, most of the remaining clang static analysis
warnings are gone.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2023-03-14 15:38:20 -04:00
Michael Carroll
18dd05fba5 Documentation improvements on the executor (#2125)
Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>
2023-03-13 17:23:43 -05:00
Barry Xu
232262c02a Avoid losing waitable handles while using MultiThreadedExecutor (#2109)
Signed-off-by: Barry Xu <barry.xu@sony.com>
2023-03-13 10:10:24 -07:00
Chris Lalancette
6c4afb3a70 Hook up the incompatible type event inside of rclcpp (#2069)
* Rename QOSEventHandler* to EventHandler.

We are going to be using it for more than just QOS events, so
rename it to just EventHandler and EventHandlerBase for now.
Leave the old names in place but deprecated.

* Rename qos_event.hpp -> event_handler.hpp
* Revamp incompatible_qos callback setting.
* Add in incompatible type implementation.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2023-03-13 09:33:30 -04:00
Chris Lalancette
b6a803f48c Update all rclcpp packages to C++17. (#2121)
The main reason to do this is so that we can compile rclcpp
with the clang static analyzer.  As of clang++-14 (what is in
Ubuntu 22.04), the default still seems to be C++14, so we need
to specify C++17 so that new things in the rclcpp headers work
properly.

Further, due to reasons I don't fully understand, I needed to
set CMAKE_CXX_STANDARD_REQUIRED in order for clang to really use
that version.  So set this as well.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2023-03-07 14:43:58 -05:00
Chris Lalancette
dbe555a3c3 Use the correct macro for LifecycleNode::get_fully_qualified_name (#2117)
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-03-06 12:45:24 -05:00
mauropasse
1a9b117d53 Fix clang warning: bugprone-use-after-move (#2116)
Signed-off-by: Mauro Passerino <mpasserino@irobot.com>
Co-authored-by: Mauro Passerino <mpasserino@irobot.com>
2023-03-05 12:53:14 -05:00
Steve Macenski
11778f5048 add get_fully_qualified_name to rclcpp_lifecycle (#2115)
Signed-off-by: stevemacenski <stevenmacenski@gmail.com>
2023-03-04 16:13:56 -05:00
Nathan Wiebe Neufeldt
399f4df739 Fix the GoalUUID to_string representation (#1999)
* Fix expected results of the goal_uuid_to_string test

Signed-off-by: Nathan Wiebe Neufeldt <nwiebeneufeldt@clearpath.ai>
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
2023-03-02 07:45:22 -05:00
Chris Lalancette
e7890b7c62 19.3.0 2023-03-01 14:27:21 +00:00
Chris Lalancette
b589b490c3 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-03-01 14:27:01 +00:00
Christophe Bedard
72c05ecee0 Fix memory leak in tracetools::get_symbol() (#2104)
Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
2023-02-28 16:42:39 -06:00
Brian
968ce0a03f Service introspection (#1985)
* Implementation of service introspection.

To do this, we add a new method on the Client and
Service classes that allows the user to change the
introspection method at runtime.  These end up calling
into the rcl layer to do the actual configuration,
at which point service introspection messages will be
sent as configured.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
Signed-off-by: Brian Chen <brian.chen@openrobotics.org>
2023-02-28 13:43:39 -05:00
Miguel Company
3062dec77e Allow publishing borrowed messages with intra-process enabled (#2108)
Signed-off-by: Miguel Company <MiguelCompany@eprosima.com>
2023-02-24 14:48:23 -08:00
Chen Lihui
9ea55ba620 to fix flaky test about TestTimeSource.callbacks (#2111)
Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2023-02-24 15:16:02 -05:00
Chris Lalancette
f57f4077fd 19.2.0 2023-02-24 18:27:42 +00:00
Chris Lalancette
006d1fa1df Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-02-24 18:27:32 +00:00
Chen Lihui
b1e834a8df to create a sublogger while getting child of Logger (#1717)
* to create a sublogger while getting child of Logger

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2023-02-24 11:03:10 -05:00
Silvio Traversaro
28e4b1bd73 Fix documentation of Context class (#2107)
Signed-off-by: Silvio Traversaro <silvio@traversaro.it>
2023-02-16 16:32:10 -05:00
Alberto Soragna
35a5d6a66c fixes for rmw callbacks in qos_event class (#2102)
Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2023-02-16 07:56:47 -05:00
Chris Lalancette
01b19247f1 19.1.0 2023-02-14 14:36:12 +00:00
Chris Lalancette
15ea024d48 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-02-14 14:35:58 +00:00
mauropasse
ce5a2614fa Add support for timers on reset callback (#1979)
Signed-off-by: Mauro Passerino <mpasserino@irobot.com>
Co-authored-by: Alberto Soragna <alberto.soragna@gmail.com>
2023-02-10 08:25:52 -08:00
Chen Lihui
beda0966db Topic node guard condition in executor (#2074)
* add a test

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* rollback the node guard condition for exectuor

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

---------

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2023-02-10 11:39:27 +00:00
Barry Xu
1fd5a96561 Fix bug on the disorder of calling shutdown callback (#2097)
* Fix bug on the disorder of calling shutdown callback

Signed-off-by: Barry Xu <barry.xu@sony.com>
2023-02-06 12:46:47 -05:00
Shane Loretz
be8c5d01c6 19.0.0
Signed-off-by: Shane Loretz <sloretz@openrobotics.org>
2023-01-30 18:26:56 -08:00
Shane Loretz
97c5c11c25 Add default constructor to NodeInterfaces (#2094)
* Add default constructor to NodeInterfaces

Signed-off-by: Shane Loretz <sloretz@openrobotics.org>

* Remove unnecessary NOLINT

Signed-off-by: Shane Loretz <sloretz@google.com>

---------

Signed-off-by: Shane Loretz <sloretz@openrobotics.org>
Signed-off-by: Shane Loretz <sloretz@google.com>
2023-01-30 13:47:11 -08:00
Chris Lalancette
7d660acc05 Fix clock state cached time to be a copy, not a reference. (#2092)
That is, in cache_last_msg(), we were just taking a shared_ptr
reference.  While this is pretty fast, it also means that
any changes to that message would be reflected internally.
Instead, make a new shared pointer out of that message when
it comes in, which essentially causes this to be a copy.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2023-01-27 14:16:31 -05:00
Michael Carroll
ab71df3ce1 Improve component_manager_isolated shutdown (#2085)
This eliminates a potential hang when the isolated container is being
shutdown via the rclcpp SignalHandler.

Signed-off-by: Michael Carroll <michael@openrobotics.org>
Co-authored-by: Chris Lalancette <clalancette@openrobotics.org>
2023-01-23 09:46:50 -06:00
Alexander Hans
37adc03c11 Fix -Wmaybe-uninitialized warning (#2081)
* Fix -Wmaybe-uninitialized warning

gcc 12 warned about `callback_list_ptr` potentially being uninitialized
when compiling in release mode (i.e., with `-O2`). Since `shutdown_type`
is a compile-time parameter, we fix the warning by enforcing the
decision at compile time.

Signed-off-by: Alexander Hans <ahans@users.noreply.github.com>
2023-01-17 14:50:44 -05:00
Chris Lalancette
3db2ece145 Fix the keep_last warning when using system defaults. (#2082)
If the user creates SystemDefaultsQoS setting, they are
explicitly asking for SystemDefaults.  In that case, we should
*not* warn, and just let the underlying RMW choose what it
wants.  Implement that here by passing a boolean parameter
through that decides when we should print out the warning,
and then skip printing that warning when SystemDefaultsQoS
is created.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2023-01-13 13:47:13 -08:00
Chris Lalancette
1bbb03302a Add in a fix for older compilers. (#2075)
* Add in a fix for older compilers.

The addition of the NodeInterfaces class made it stop compiling
with older compilers (such as gcc 9.4.0 on Ubuntu 20.04).
The error has to do with calling the copy constructor on
rclcpp::Node, which is deleted.  Work around this by removing
the NodeInterfaces shared_ptr constructor, which isn't technically
needed.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2023-01-04 08:49:57 -05:00
Shane Loretz
c63f9eae0f 18.0.0
Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2022-12-29 10:30:32 -08:00
methylDragon
a73e0bd23b Implement Unified Node Interface (NodeInterfaces class) (#2041)
Co-authored-by: William Woodall <william+github@osrfoundation.org>
Co-authored-by: methylDragon <methylDragon@gmail.com>
2022-12-28 17:59:02 -08:00
jrutgeer
c5491a4e58 API url info fix (#2071)
* Fixed API url info.

Signed-off-by: jrutgeer <johan.rutgeerts@lancewood.eu>

* Fix api url info in README

Signed-off-by: jrutgeer <johan.rutgeerts@lancewood.eu>

Signed-off-by: jrutgeer <johan.rutgeerts@lancewood.eu>
2022-12-23 10:27:42 -03:00
Alberto Soragna
3fb012e2e9 do not throw exception if trying to dequeue an empty intra-process buffer (#2061)
Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2022-12-21 10:11:24 +00:00
methylDragon
9c1c9896a3 Move event callback binding to PublisherBase and SubscriptionBase (#2066) 2022-12-19 18:21:40 -08:00
methylDragon
c091fe1a45 Implement validity checks for rclcpp::Clock (#2040) 2022-12-19 18:18:54 -08:00
mauropasse
a20a295a3b Set explicitly callback type (#2059)
* Set explicitly callback type

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Revert "Set explicitly callback type"

This reverts commit dfb4c54adb.

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Add type info to cpp_callback_trampoline

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>
Co-authored-by: Mauro Passerino <mpasserino@irobot.com>
2022-12-16 09:44:59 +00:00
Mateusz Szczygielski
86335dd4ac Fix logging macros to build with msvc and cpp20 (#2063)
Signed-off-by: Mateusz Szczygielski <mateusz.szczygielski@robotec.ai>

Signed-off-by: Mateusz Szczygielski <mateusz.szczygielski@robotec.ai>
2022-12-13 15:40:38 -03:00
Jeffery Hsu
432bf21f02 Add clock type to node_options (#1982)
* add clock type to node_options and change node/lifecycle_node constructor accordingly

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>

* Modify TimeSource::NodeState class to work with different clock types. Add test cases.

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>

* Change on_parameter_event to output RCLCPP_ERROR and check
ros_time_active_ in ClocksState::attachClock()

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>

* Remove a redundant include

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>

* Disallow setting use_sim_time to true if a clock_type can't support it.
Following the reasoning in c54a6f1cd2, on_set_parameters doesn't try to enforce use_sim_time to be of boolean type explicitly.

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>

* minior style change

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>

* remove reason string for successful result

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>

Signed-off-by: Jeffery Hsu <jefferyyjhsu@gmail.com>
2022-12-13 09:11:09 -08:00
andrei
1ac37b692c fix nullptr dereference in prune_requests_older_than (#2008)
* fix nullptr dereference in prune_requests_older_than

Signed-off-by: akela1101 <akela1101@gmail.com>

* add tests for prune_requests_older_than

Signed-off-by: akela1101 <akela1101@gmail.com>

* Update rclcpp/test/rclcpp/test_client.cpp

Co-authored-by: Chen Lihui <lihui.chen@sony.com>
Signed-off-by: akela1101 <akela1101@gmail.com>

Signed-off-by: akela1101 <akela1101@gmail.com>
Co-authored-by: Chen Lihui <lihui.chen@sony.com>
2022-12-13 10:31:14 -03:00
methylDragon
338eed0c06 Remove templating on to_rcl_subscription_options (#2056) 2022-12-06 11:19:40 -08:00
Lei Liu
66b19448b0 Fix SharedFuture from async_send_request never becomes valid (#2044)
Signed-off-by: Lei Liu <Lei.Liu.AP@sony.com>
2022-12-01 18:17:43 -08:00
Chris Lalancette
a00ef22d6d Add in a warning for a KeepLast depth of 0. (#2048)
* Add in a warning for a KeepLast depth of 0.

It really doesn't make much sense to have a KeepLast depth of 0;
no data could possibly be stored.  Indeed, the underlying DDS
implementations don't actually support this.  It currently "works"
because a KeepLast depth of 0 is assumed to be system default,
so the RMW layer typically chooses "1" instead.  But this isn't
something we should be encouraging users to do, so add a warning.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-11-30 08:31:53 -05:00
Shane Loretz
e5d20474da Mark rclcpp::Clock::now() as const (#2050)
Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2022-11-23 08:44:34 -08:00
Chen Lihui
91bc312190 fix a case that not throw ParameterUninitializedException (#2036)
* fix a case that not throw ParameterUninitializedException

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* catch ParameterUninitializedException exception while calling get_parameters in service callback

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update doc

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* add one more test

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* explicitly use this to call a method inside the class itself

Co-authored-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
Signed-off-by: Chen Lihui <lihui.chen@sony.com>

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
Co-authored-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2022-11-09 07:50:01 -08:00
Audrow Nash
82f1fbff0b [rolling] Update maintainers (#2043)
* Update maintainers to Ivan Paunovic, Michel Hidalgo, and William Woodall

Signed-off-by: Audrow Nash <audrow@openrobotics.org>
2022-11-08 08:21:43 -05:00
Chris Lalancette
7c6785176a 17.1.0 2022-11-02 18:06:21 +00:00
Chris Lalancette
586932ebf8 Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-11-02 18:06:12 +00:00
Tomoya Fujita
edbfe1404b LifecycleNode on_configure doc fix. (#2034)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2022-10-28 09:17:47 -07:00
Tomoya Fujita
6f22443513 MultiThreadExecutor number of threads is at least 2+ in default. (#2032)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2022-10-28 09:17:23 -07:00
Tomoya Fujita
e5d13a2478 Bugfix 20210810 get current state (#1756)
* protect state_machine_ with mutex lock.

protect state_handle_ with mutex lock.

reconsider mutex lock scope.

remove mutex lock from constructors.

lock just once during initialization of LifecycleNodeInterfaceImpl.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* Move updating of current_state to right after initialization.

This is slightly more correct in the case that registering one
of the services fails.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
Co-authored-by: Chris Lalancette <clalancette@openrobotics.org>
2022-10-28 09:15:14 -07:00
Chen Lihui
d119157948 Fix bug that a callback not reached (#1640)
* Add a test case

a subscriber on a new executor with a callback group triggered to receive a message

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* fix flaky and not to use spin_some

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update comment

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update for not using anti-pattern source code

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* add a notify guard condition for callback group

Co-authored-by: William Woodall <william@osrfoundation.org>
Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* Notify guard condition of Node not to be used in Executor

it is only for the waitset of GraphListener

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* put code in the try catch

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* defer to create guard condition

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* use context directly for the create function

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* cpplint

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* fix that some case might call add_node after shutdown

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* nitpick and fix some potential bug

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* add sanity check as some case might not create notify guard condition after shutdown

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* Cleanup includes.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* remove destroy method

make a callback group can only create one guard condition

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* remove limitation that guard condition can not be re-created in callback group

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
Co-authored-by: William Woodall <william@osrfoundation.org>
Co-authored-by: Chris Lalancette <clalancette@openrobotics.org>
2022-10-26 14:18:21 -07:00
Alexis Paques
85c0af4fa0 Set the minimum number of threads of the Multithreaded executor to 2 (#2030)
* Set the minimum number of threads of the Multithreaded executor to 2

Signed-off-by: Alexis Paques <paa1ti@bosch.com>
2022-10-25 13:33:14 -04:00
Chris Lalancette
2d32d03ba3 Make lifecycle impl get_current_state() const. (#2031)
We should only need to update the current state when it changes,
so we do that in the change_state method (which is not const).
Then we can just return the current_state_ object in
get_current_state, and then mark it as const.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-10-24 17:14:12 -04:00
Chris Lalancette
28890bf126 Cleanup the lifecycle implementation (#2027)
* Split lifecycle_node_interface_impl into header and implementation.

There is no reason it should all be in the header file.  No
functional change.

* Mark LifecycleNodeInterfaceImpl as final.

* Update documentation about return codes.

* Mark a bunch of LifecycleNodeInterfaceImpl methods as const.

* Make most of LifecycleNodeInterfaceImpl private.

* Mark some LifecycleNode methods as const.

* Disable copies on LifecycleNodeInterfaceImpl.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-10-24 08:43:17 -04:00
uupks
b9b1468d15 check thread whether joinable before join (#2019)
Signed-off-by: uupks <uupks0325@gmail.com>
2022-10-13 08:30:02 -04:00
Cristóbal Arroyo
3aca271ef5 Set cpplint test timeout to 3 minutes (#2022)
Signed-off-by: Crola1702 <cristobal.arroyo@ekumenlabs.com>
2022-10-10 08:17:24 -05:00
Chris Lalancette
dec766228d Cleanup the rclcpp_lifecycle dependencies. (#2021)
That is, make sure they are all listed in package.xml, found
in the CMakeLists.txt, and properly included where they are
used.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-10-04 14:04:12 -04:00
Chris Lalancette
95837d34f1 Make sure to include-what-you-use in the node_interfaces. (#2018)
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-09-29 07:54:41 -04:00
mauropasse
145933b037 Do not clear entities callbacks on destruction (#2002)
* Do not clear entities callbacks on destruction

Removing these clearings since they were not necessary,
since the objects are being destroyed anyway.

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Fix CI

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Restore clear_on_ready_callback on ~QOSEventHandlerBase

Needed since QOSEventHandlerBase does not own
the pub/sub listeners. So the QOSEventHandler
can be destroyed while the corresponding listeners
are still alive, so we need to clear these callbacks.

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Add coment on clearing callback for QoS event

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>
Co-authored-by: Mauro Passerino <mpasserino@irobot.com>
2022-09-23 00:30:59 +01:00
Chen Lihui
6a8c61c026 use unique ptr and remove unuseful container (#2013)
Signed-off-by: Chen Lihui <lihui.chen@sony.com>

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2022-09-19 10:08:25 -07:00
Chen Lihui
978439191f fix mismatched issue if using zero_allocate (#1995)
* fix mismatched issue if uzing zero_allocated

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2022-09-15 08:17:28 -04:00
Chris Lalancette
7bc05da5d1 17.0.0 2022-09-13 20:29:01 +00:00
Chris Lalancette
4744fb6f50 Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-09-13 20:28:54 +00:00
Barry Xu
d0e1e837b5 Make ParameterService and Sync/AsyncParameterClient accept rclcpp::QoS (#1978)
* Make ParameterService and Sync/AsyncParameterClient accept rclcpp::QoS

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Avoid deprecated function using another deprecated function

Signed-off-by: Barry Xu <barry.xu@sony.com>

Signed-off-by: Barry Xu <barry.xu@sony.com>
2022-09-09 15:06:33 -07:00
Chen Lihui
92d4f3e347 support regex match for parameter client (#1992)
* support regex match for parameter client

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* address review that change behavior of a public method

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* remove an unnecessary comment

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update gmock compilation setting

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2022-09-08 12:55:41 -07:00
Tyler Weaver
ea8daa3784 operator+= and operator-= for Duration (#1988)
* operator+= and operator-= for Duration

Signed-off-by: Tyler Weaver <maybe@tylerjw.dev>
2022-09-02 13:58:56 -04:00
Ivan Santiago Paunovic
df994e435d Revert "Revert "Add a create_timer method to Node and LifecycleNode classes (#1975)" (#2009) (#2010)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2022-08-31 10:21:13 -03:00
schrodinbug
93222cc2cd force compiler warning if callback handles not captured (#2000)
clarify documentation to show that not capturing returned handles
will result in callbacks immediately being unregistered

Signed-off-by: Jason Beach <jason.m.beach@gmail.com>
2022-08-31 08:40:11 -04:00
Shane Loretz
11b5f8db21 Revert "Add a create_timer method to Node and LifecycleNode classes (#1975)" (#2009)
This reverts commit 6167a575b3.

Signed-off-by: Shane Loretz <sloretz@openrobotics.org>

Signed-off-by: Shane Loretz <sloretz@openrobotics.org>
2022-08-30 13:42:14 -07:00
Andrew Symington
6167a575b3 Add a create_timer method to Node and LifecycleNode classes (#1975)
Signed-off-by: Andrew Symington <andrew.c.symington@gmail.com>
2022-08-30 10:10:11 -03:00
Brian
dab9f5e0a3 [docs] add note about callback lifetime for {on, post}_set_parameter_callback (#1981)
[docs] add note about {on, post, pre}_set_parameter_callback lifetime

Signed-off-by: Brian Chen <brian.chen@openrobotics.org>
2022-08-29 15:14:09 -04:00
Chen Lihui
3d69031d2a fix memory leak (#1994)
Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2022-08-17 21:30:51 -07:00
Deepanshu Bansal
b953bdddf8 Support pre-set and post-set parameter callbacks in addition to on-set-parameter-callback. (#1947)
* Support add_pre_set_parameter and add_post_set_parameter callbacks in addition to add_on_set_parameter_callback in Node API

Signed-off-by: deepanshu <deepanshubansal01@gmail.com>
2022-07-14 18:22:48 -04:00
Shane Loretz
64e4c72791 Make create_service accept rclcpp::QoS (#1969)
Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2022-07-12 09:41:40 +09:00
Shane Loretz
f6056beaa0 Make create_client accept rclcpp::QoS (#1964)
* Make create_client accept rclcpp::QoS

Signed-off-by: Shane Loretz <sloretz@openrobotics.org>

* Deprecate passing rmw_qos_profile_t to create_client

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2022-07-11 10:09:44 -07:00
Chris Lalancette
37b589dc85 Fix the documentation for rclcpp::ok to be accurate. (#1965)
That is, it returns false if shutdown has been called, and
true in all other circumstances.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-07-07 09:07:12 -07:00
Chen Lihui
6dd3a0377b use regex for wildcard matching (#1839)
* use regex for wildcard matching

Co-authored-by: Aaron Lipinski <aaron.lipinski@roboticsplus.co.nz>
Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* use map to process the content of parameter file by order

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* add more test cases

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* try to not decrease the performance and make the param win last

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update node name

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update document comment

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* add more test for parameter_map_from

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

Co-authored-by: Aaron Lipinski <aaron.lipinski@roboticsplus.co.nz>
2022-07-06 09:41:16 -07:00
Audrow Nash
33dae5d679 Mirror rolling to master 2022-06-28 09:20:48 -05:00
William Woodall
f43a9198eb Revert "Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (#1821) (#1874)" (#1956)
This reverts commit 3c8e89d17c.
2022-06-24 11:21:24 -07:00
Hubert Liberacki
3c8e89d17c Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (#1821) (#1874) 2022-06-24 00:33:29 -07:00
Tomoya Fujita
546ddf87fe test adjustment for LoanedMessage. (#1951)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2022-06-22 15:01:43 -07:00
William Woodall
dbded5c0d6 fix virtual dispatch issues identified by clang-tidy (#1816)
* fix virtual dispatch issues identified by clang-tidy

Signed-off-by: William Woodall <william@osrfoundation.org>

* fix up to reduce code duplication

Signed-off-by: William Woodall <william@osrfoundation.org>

* uncrustify

Signed-off-by: William Woodall <william@osrfoundation.org>

* avoid returning temporaries

Signed-off-by: William Woodall <william@osrfoundation.org>

* uncrustify

Signed-off-by: William Woodall <william@osrfoundation.org>

* add docs about overriding methods used in constructors

Signed-off-by: William Woodall <william@osrfoundation.org>
2022-06-21 18:59:25 -07:00
Nikolai Morin
86a9d5882e Remove unused on_parameters_set_callback_ (#1945)
Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>
2022-06-14 13:22:53 -03:00
Ivan Santiago Paunovic
8e6a6fb32d Fix subscription.is_serialized() for callbacks with message info (#1950)
* Fix subscription.is_serialized() for callbacks with message info argument

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>

* Add tests + please linters

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2022-06-10 17:18:25 -03:00
Tomoya Fujita
b3f57033a9 wait for subscriptions on another thread. (#1940)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2022-06-09 12:14:12 -07:00
Daniel Reuter
38581cc860 Fix documentation of RCLCPP_[INFO,WARN,...] (#1943)
In the pull request https://github.com/ros2/rclcpp/pull/1442 the ability
to use `std::string` as the first argument to the logging functions was
(rightfully) removed.

This commit just corrects the documentation of the macro, since it
confused me a bit ;)

Signed-off-by: Daniel Reuter <daniel.robin.reuter@googlemail.com>
2022-06-07 11:56:57 -04:00
Alberto Soragna
790e529ba3 Always trigger guard condition waitset (#1923)
* trigger guard condition waitset regardless of whether a trigger callback is present

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* restore mutex in guard_condition.cpp

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* remove whitespace

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* add unit-test

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* add documentation for trigger and set_on_trigger_callback

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2022-06-02 18:58:19 +01:00
Barry Xu
5c688303b3 Add statistics for handle_loaned_message (#1927)
* Add statistics for handle_loaned_message

Signed-off-by: Barry Xu <barry.xu@sony.com>
2022-05-19 08:10:17 -07:00
Jochen Sprickerhof
02802bcc38 Drop wrong template specialization (#1926)
This fails with g++ -std=gnu++20.

Signed-off-by: Jochen Sprickerhof <git@jochen.sprickerhof.de>
2022-05-12 19:08:34 -07:00
Jacob Perron
491475f232 16.2.0 2022-05-03 12:14:26 -07:00
Barry Xu
b8b64b4c08 Update get_parameter_from_event to follow the function description (#1922)
Signed-off-by: Barry Xu <barry.xu@sony.com>
2022-05-03 11:21:20 -07:00
Jacob Perron
ee67c211c5 Add 'best available' QoS enum values and methods (#1920)
If users set a policy as 'best available', then the middleware will pick a policy
that is most compatible with the current set of discovered endpoints while maintaining
the highest level of service possible.

For details about the expected behavior, see connected changes:

- https://github.com/ros2/rmw/pull/320
- https://github.com/ros2/rmw_dds_common/pull/60

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2022-05-03 10:35:10 -07:00
Audrow Nash
82ddd44140 16.1.0
Signed-off-by: Audrow Nash <audrow@hey.com>
2022-04-29 17:40:56 -07:00
Tomoya Fujita
a1980678ae use reinterpret_cast for function pointer conversion. (#1919)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2022-04-26 13:39:00 -07:00
Audrow Nash
c24e485084 16.0.1
Signed-off-by: Audrow Nash <audrow@hey.com>
2022-04-13 18:17:29 -07:00
Chen Lihui
d99157d731 remove DEFINE_CONTENT_FILTER cmake option (#1914)
* remove DEFINE_CONTENT_FILTER cmake option

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* remove the macro CONTENT_FILTER_ENABLE as well

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2022-04-11 10:26:09 -03:00
William Woodall
248d911ea5 16.0.0 2022-04-08 16:27:59 -07:00
William Woodall
76aae4f799 changelogs
Signed-off-by: William Woodall <william@osrfoundation.org>
2022-04-08 16:25:08 -07:00
William Woodall
6815022909 remove things that were deprecated during galactic (#1913)
Signed-off-by: William Woodall <william@osrfoundation.org>
2022-04-08 16:23:43 -07:00
Audrow Nash
85a7046ac3 15.4.0
Signed-off-by: Audrow Nash <audrow@hey.com>
2022-04-05 14:17:00 -07:00
Alberto Soragna
6c06a29050 add take_data_by_entity_id API to waitable (#1892)
* add take_data_by_entity_id API to waitable

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* use size_t for entity id

Signed-off-by: William Woodall <william@osrfoundation.org>

Co-authored-by: William Woodall <william@osrfoundation.org>
2022-04-04 22:25:30 -07:00
Chen Lihui
03fa731d23 add content-filtered-topic interfaces (#1561)
* to support a feature of content filtered topic

Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>

* update for checking memory allocated

Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>

* set expression parameter only if filter is valid

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* add test

Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>

* use a default empty value for expresion parameters

Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>

* remove std_msgs dependency

Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>

* use new rcl interface

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* remove unused include header files and fix unscrutify

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update comment

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update comment

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* rename

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* refactor test

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* relate to `rcutils_string_array_t expression_parameters` changed in rmw

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* remove the implementation temporary, add them with fallback in the feature

1. add DEFINE_CONTENT_FILTER with default(ON) to build content filter interfaces
2. user need a compile option(CONTENT_FILTER_ENABLE) to turn on the feature
to set the filter or call the interfaces

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update comments and check the option to build content filter test

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* add DDS content filter implementation

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* address review

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* rcl api changed

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* increase the filter propagation time

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* add rclcpp::ContentFilterOptions and use it as the return type of get_content_filter

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* increase the maximun time to wait message event and content filter propagation

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* cft member should be defined in the structure.

to check the macro for interfaces is enough.

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* set test timeout to 120

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update doc

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2022-04-04 11:50:50 +08:00
Chris Lalancette
0699aeb851 15.3.0 2022-03-30 18:54:18 +00:00
Chris Lalancette
06e6da414a Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-03-30 18:54:09 +00:00
Abrar Rahman Protyasha
12de518956 [NodeParameters] Set name in param info pre-check (#1908)
* [NodeParameters] Set name if user didn't populate

If the user provided parameter descriptor already contains a name, then
we should not override said name, under the good faith assumption that
the user knows what they are doing.

Signed-off-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>
2022-03-30 09:57:22 -07:00
Gaël Écorchard
eac0063176 Add test-dep ament_cmake_google_benchmark (#1904)
Signed-off-by: Gaël Écorchard <gael.ecorchard@cvut.cz>
2022-03-28 09:23:11 -04:00
Barry Xu
492770c12f Add publish by loaned message in GenericPublisher (#1856)
* Add publish by loaned message in GenericPublisher

Signed-off-by: Barry Xu <barry.xu@sony.com>
Co-authored-by: Alban Tamisier <alban.tamisier@apex.ai>
2022-03-27 22:06:17 -07:00
Jacob Perron
d302e3c628 15.2.0 2022-03-24 17:37:17 -07:00
Scott K Logan
011ea39e99 Add missing ament dependency on rcl_interfaces (#1903)
This package uses rcl_interfaces directly, and we've been getting away
with the missing dependency because `rcl` has the entirety of
`rcl_interfaces` as part of its link interface even tough it doesn't
need to.

If (when) `rcl` scopes its dependency to only the c generator and drops
the cpp generator from its link interface, this package will fail to
find the cpp symbols at link time. This change remedies that.

Signed-off-by: Scott K Logan <logans@cottsay.net>
2022-03-22 15:53:08 -07:00
Andrea Sorbini
49c2dd4813 Update data callback tests to account for all published samples. (#1900)
* Update data callback tests to account for all published samples.

Signed-off-by: Andrea Sorbini <asorbini@rti.com>
2022-03-21 13:50:04 -07:00
Andrea Sorbini
6afec4805c Increase timeout for acknowledgments to account for slower Connext settings. (#1901)
Signed-off-by: Andrea Sorbini <asorbini@rti.com>
2022-03-21 10:29:08 -04:00
Hirokazu Ishida
9ae35e347e Select executor in node registration (#1898)
* Select executor

Signed-off-by: Hirokazu Ishida <h-ishida@jsk.imi.i.u-tokyo.ac.jp>

* Fix indent

Signed-off-by: Hirokazu Ishida <h-ishida@jsk.imi.i.u-tokyo.ac.jp>
2022-03-18 20:42:06 +00:00
William Woodall
0f58bb8700 clang-tidy: explicit constructors (#1782)
* mark some single-argument constructors explicit that should have been

Signed-off-by: William Woodall <william@osrfoundation.org>

* suppress clang-tidy [google-explicit-constructor] in some cases where it is a false-positive

Signed-off-by: William Woodall <william@osrfoundation.org>

* Revert "suppress clang-tidy [google-explicit-constructor] in some cases where it is a false-positive"

This reverts commit eb6bf7e2df0dd27c945e97584ba9902ef9f61305.

Signed-off-by: William Woodall <william@osrfoundation.org>
2022-03-16 13:58:49 -07:00
mauropasse
8b9cabfb9d Add client/service QoS getters (#1784)
Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

Co-authored-by: Mauro Passerino <mpasserino@irobot.com>
2022-03-16 18:05:58 +00:00
Chris Lalancette
2e39e09803 Fix a bunch more rosdoc2 issues in rclcpp. (#1897)
* Fix a bunch more rosdoc2 issues in rclcpp.

There are a smattering of problems in here:

1.  We weren't properly using PREDEFINE for all of our macros.
2.  The Doxyfiles were referencing tag files that may not exist
(this will be handled by rosdoc2 automatically).
3.  The C++ parser in doxygen can't handle "friend classname",
but can handle "friend class classname"; it shouldn't matter
one way or the other to the compiler.
4.  There were a couple of parameters that were not documented.
5.  The doxygen C++ parser can't handle decltype in all situations.
6.  There was a structure using a C-style declaration.

This patch fixes all of the above issues.  We still aren't totally
clean on a rosdoc2 build, but we are a lot closer.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-03-11 14:46:07 -05:00
mauropasse
91f0b64493 time_until_trigger returns max time if timer is cancelled (#1893)
* time_until_trigger returns max time if timer is cancelled

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>
2022-03-10 20:36:16 -08:00
Chris Lalancette
3bd6900f98 Micro-optimizations in rclcpp (#1896)
* Use a single call to collect all CallbackGroup pointers.

Believe it or not, the taking and releasing of mutex_ within
the CallbackGroup class shows up in profiles.  However, when
collecting entities we really don't need to take it and drop
it between each of subscriptions, services, clients, timers,
and waitables.  Just take it once at the beginning, collect
everything, and then return, which removes a lot of unnecessary
work with that mutex.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Pass shared_ptr as constref in the MemoryStrategy class.

That way, in the case that the callee doesn't need to take
a reference, we avoid creating and destroying a shared_ptr
class.  This reduces the overhead in using these functions,
and seems to work fine in the default case.  If a user wants
to subclass the MemoryStrategy class, then they can explicitly
create a shared_ptr copy by using the copy constructor.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Use constref shared_ptr when iterating.

Believe it or not, the creation and destruction of the
shared_ptr class itself shows up in profiles in these loops.
Since we don't need to hold onto a reference while iterating
(the class is already doing that), just use constref wherever
we can which drastically reduces the overhead.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-03-09 11:13:36 -08:00
Alberto Soragna
f2f7ffdf53 fix bugprone-exception-escape in node_main.cpp.in (#1895)
Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2022-03-08 19:55:06 +00:00
Chris Lalancette
16914e31a1 15.1.0 2022-03-01 19:33:31 +00:00
Chris Lalancette
4e3c6be76a Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-03-01 19:33:22 +00:00
Tomoya Fujita
79241a3cdc spin_all with a zero timeout. (#1878)
* spin_all with a zero timeout.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2022-02-25 09:20:00 -08:00
Alberto Soragna
9c5ad79b63 Merge pull request #1889 from ros2/asoragna/improve-components-main
small improvements to node_main.cpp.in
2022-02-24 17:30:40 +00:00
iRobot ROS
d8e1aed520 Add RMW listener APIs (#1579)
* Add RMW listener APIs

Signed-off-by: Alberto Soragna <asoragna@irobot.com>

* split long log into two lines

Signed-off-by: Alberto Soragna <asoragna@irobot.com>

* Remove use_previous_event

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Do not set gc listener callback

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* significant refactor to make callbacks type safe

Signed-off-by: William Woodall <william@osrfoundation.org>

* Add on_ready callback to waitables, add clear_* functions, add unit-tests

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* add mutex to set and clear listener APIs

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* allow to set ipc sub callback from regular subscription

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* fix minor failures

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* fix typos and errors in comments

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* fix comments

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* expose qos listener APIs from pub and sub; add unit-tests

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* add qos event unit-test for invalid callbacks

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* Use QoS depth to limit callbacks count

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* fix ipc-subscription

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* Rename CallbackMessageT -> ROSMessageType

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Set callbacks to Actions

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* changes from upstream

Signed-off-by: William Woodall <william@osrfoundation.org>

* Unset callback on entities destruction

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* fix rebase errors

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* fix unit-tests

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* Add GuardCondition on trigger callback

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Add tests for new GuardCondition APIs

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Fix windows CI

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Action unset callbacks only if were set

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* add missing include rcl event callback include directive

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* typos

Signed-off-by: William Woodall <william@osrfoundation.org>

* remove listener reference

Signed-off-by: William Woodall <william@osrfoundation.org>

* remove references to listener and move a method closer to impl

Signed-off-by: William Woodall <william@osrfoundation.org>

* cpplint

Signed-off-by: William Woodall <william@osrfoundation.org>

* Fix qos history check in subscription_intra_process.hpp

Co-authored-by: Mauro Passerino <mpasserino@irobot.com>
Co-authored-by: William Woodall <william@osrfoundation.org>
Co-authored-by: Alberto Soragna <alberto.soragna@gmail.com>
2022-02-24 00:32:17 -08:00
Miguel Company
c5a16dce11 Remove fastrtps customization on tests (#1887)
Signed-off-by: Miguel Company <MiguelCompany@eprosima.com>
2022-02-22 08:49:37 -05:00
Alberto Soragna
32c03dde2d small improvements to node_main.cpp.in
Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2022-02-19 11:57:10 +00:00
Shane Loretz
4f778199b4 Install headers to include/${PROJECT_NAME} (#1888)
* initial attempt, problems with ament_gen_version_h

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* remove blank line

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2022-02-16 09:41:21 -08:00
Shane Loretz
025cd5ccc8 Use ament_generate_version_header (#1886)
Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2022-02-15 13:02:23 -08:00
Tomoya Fujita
4c8cfa39f8 use universal reference to support rvalue. (#1883)
* use universal reference to support rvalue.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2022-02-10 09:58:36 -08:00
Chen Lihui
891fff0153 fix one subscription can wait_for_message twice (#1870)
Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2022-02-10 08:44:14 -05:00
Alberto Soragna
43db06dad7 Use spin() in component_manager_isolated.hpp (#1881)
* replace spin_until_future_complete with spin in component_manager_isolated.hpp

spin_until_future_complete() is more inefficient as it needs to check the state of the future and the timeout after every work iteration

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* fix uncrustify error

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2022-02-09 11:45:39 -03:00
Tomoya Fujita
0d1747e066 LifecycleNode::on_deactivate deactivate all managed entities. (#1885)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2022-02-07 09:32:44 -08:00
Kenji Miyake
2520d398c7 Add return value version of get_parameter_or (#1813)
* Add return value version of get_parameter_or

* Add test case

Signed-off-by: Kenji Miyake <kenji.miyake@tier4.jp>
Co-authored-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>
2022-02-04 09:23:17 -05:00
Alberto Soragna
d3c0049b24 Merge pull request #1871 from ros2/asoragna/executor-is-spinning
add is_spinning() method to executor base class
2022-01-21 08:43:04 +00:00
Chris Lalancette
c54a6f1cd2 Cleanup time source object lifetimes (#1867)
* Small cleanups in TimeSource.

Simplify some code, and also make sure to throw an exception
when use_sim_time is not of type bool.  Also add a test for
the latter.

* Remove the sim_time_cb_handler.

It was originally used to make sure that someone didn't change
the 'use_sim_time' type from boolean to something else.  But
since the parameters interface now does that automatically for
us, we don't need the explicit check here.

I can think of one situation that this allows that wasn't allowed
before.  If the user defined 'use_sim_time' as a parameter override
when constructing a node, and the type is bool, and they also
defined the parameters as 'dynamic_typing', then this callback
will still have effect.  But presumably if the user went out of
their way to change the parameter to dynamic_typing, they are
trying to do something esoteric and so we should just let them.

* ClocksState does not need to be a pointer.

Instead, make it a regular member variable.  That lets us get
rid of all of the special handling for when it is a weak_ptr
or not.  It's lifetime is now just that of NodeState.

* Stop using NodeState as a weak_ptr in the captures.

This ended up causing the lifetime of the object to be weird.
Instead, just capture 'this' which is sufficient.

* Make sure destroy_clock_sub is first.

* Switch to using just a regular object.

Windows objects to trying to do "make_shared" in the RCLCPP
macro, so just switch to a normal object here.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-01-20 16:30:55 -05:00
Alberto Soragna
9ec0393e63 add is_spinning() method to executor base class
Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2022-01-20 12:55:07 +00:00
gezp
bca3fd7da1 add use_global_arguments for node options of component nodes (#1776)
* add use_global_arguments for node options of component nodes

Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>

keep use_global_arguments false default

Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>

update warning message

Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>

update warnning message

Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>

add test

Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>

* use forward_global_arguments instead of use_global_arguments

Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>
2022-01-19 10:29:33 -03:00
Jacob Perron
8afef51cfd 15.0.0 2022-01-14 17:49:37 -08:00
Ivan Santiago Paunovic
3123f5a643 Automatically transition lifecycle entities when node transitions (#1863)
* Automatically transition LifecyclePublisher(s) between activated and inactive

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>

* Fix: Add created publishers to the managed entities vector

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>

* enabled_ -> activated_

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>

* Continue setting should_log_ as before

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>

* Fix visibility attributes so it works on Windows

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2022-01-14 18:00:06 -03:00
Chris Lalancette
aa18ef51cc Cleanup the TypeAdapt tests (#1858)
* Cleanup test_publisher_with_type_adapter.

It had a lot of infrastructure that it didn't need, so remove
most of that.  Also move the creation of the node to open-coded,
since we weren't really saving anything.  Finally make sure
to reset the node pointers as appropriate, which cleans up
errant error messages.

* Cleanup test_subscription_with_type_adapter.

It had a lot of infrastructure that it didn't need, so remove
most of that.  Also move the creation of the node to open-coded,
since we weren't really saving anything.  Finally make sure
to reset the node pointers as appropriate, which cleans up
errant error messages.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-01-14 14:38:13 -05:00
Chris Lalancette
1688f05aea Cleanup includes. (#1857)
Remove ones that aren't needed, and add in ones that are
actually needed in the respective files.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-01-14 08:23:16 -05:00
Jacob Perron
80f93d1dbb Fix include order and relative paths for cpplint (#1859)
* Fix include order and relative paths for cpplint

Relates to https://github.com/ament/ament_lint/pull/324

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Use double-quotes for other includes

This is backwards compatible with older versions of cpplint.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2022-01-12 14:24:49 -08:00
Doug Smith
5e314c253e Rename stringstream in macros to a more unique name (#1862)
* Rename stringstream in macros to a more unique name

Signed-off-by: Doug Smith <douglas.smith@swri.org>
2022-01-11 17:52:52 -05:00
Gonzo
6b321edb4f Add non transform capabilities for intra-process (#1849)
That is, make it so that if both a publisher and a subscriber using intra-process
and using TypeAdaptation are the same type, we don't need to convert to
a ROS Message type on the publisher and from a ROS Message type before
delivering to the subscriber.  Instead, we store the original message type
in the subscription buffer, and deliver it straight through to the subscriber.

This has two main benefits:
1. It is better for performance; we are eliding unnecessary work.
2. We can use TypeAdaptation to pass custom handles (like hardware accelerator
    handles) between a publisher and subscriber.  That means we can avoid
    unnecessary overhead when using a hardware accelerator, like synchronizing
    between the hardware accelerator and the main CPU.

The main way this is accomplished is by causing the SubscriptionIntraProcessBuffer
to store messages of the Subscribed Type (which in the case of a ROS message type
subscriber is a ROS message type, but in the case of a TypeAdapter type is the
custom type).  When a publish with a Type Adapted type happens, it delays conversion
of the message, and passes the message type from the user down into the IntraProcessManager.

The IntraProcessManager checks to see if it can cast the SubscriptionBuffer
to the custom type being published first.  If it can, then it knows it can deliver the message directly
into the SubscriptionBuffer with no conversion necessary.  If it can't, it then sees if
the SubscriptionBuffer is of a ROS message type.  If it is, then it performs the conversion
as necessary, and then stores it.  In all cases, the Subscription is then triggered underneath
so that the message will eventually be delivered by an executor.

We also add tests to ensure that in the case where the publisher and subscriber
and using the same type adapter, no conversion happens when delivering the
message.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
Signed-off-by: Gonzalo de Pedro <gonzalo@depedro.com.ar>
2022-01-07 14:45:06 -05:00
Michel Hidalgo
8093648ee3 Fix rclcpp documentation build (#1779)
* Update Doxyfile
* Update docblocks with warnings
* Use leading * instead of trailing [] for pointer types
* Help Doxygen parse std::enable_if<> condition
* Add documentation-only SFINAE functions' declarations
* Avoid function pointer type syntax in function arguments.
* Add documentation-only SFINAE function traits.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
2022-01-07 09:36:11 -03:00
Shane Loretz
9583ec7855 Add rclcpp_components::component (#1855)
Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2022-01-06 14:31:17 -08:00
Chris Lalancette
2d6e6364cd 14.1.0 2022-01-05 10:40:02 -05:00
Chris Lalancette
5613d613cf Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-01-05 10:39:54 -05:00
M. Mostafa Farzan
7a2ee23281 Use UninitializedStaticallyTypedParameterException (#1689)
* Use UninitializedStaticallyTypedParameterException

Signed-off-by: Mohammad Farzan <m2_farzan@yahoo.com>
Co-authored-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-12-23 22:28:46 -08:00
Barry Xu
802bfc2c74 Add wait_for_all_acked support (#1662)
* Add wait_for_all_acked support

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Update the description of wait_for_all_acked

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Use rcpputils::convert_to_nanoseconds() for time conversion

Signed-off-by: Barry Xu <barry.xu@sony.com>
2021-12-20 20:36:01 -08:00
Bi0T1N
152dbc6e38 Add tests for function templates of declare_parameter (#1747)
* Add function template tests for all defined types of declare_parameter

Signed-off-by: Nico Neumann <nico.neumann@iosb.fraunhofer.de>
2021-12-20 11:56:46 -08:00
Chris Lalancette
9342c257b8 14.0.0 2021-12-17 19:24:02 +00:00
Chris Lalancette
d2e563afd5 Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-12-17 19:23:51 +00:00
Chris Lalancette
8ac848bbc2 Fixes for uncrustify 0.72 (#1844)
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-12-17 13:23:44 -05:00
Tomoya Fujita
b2b676d317 use private member to keep the all reference underneath. (#1845)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2021-12-14 16:01:34 -08:00
Daisuke Nishimatsu
ee20dd31e6 Add parameter to configure number of thread (#1708)
* Add parameter to configure number of thread

Signed-off-by: wep21 <border_goldenmarket@yahoo.co.jp>
2021-12-13 09:40:16 -08:00
gezp
0775e2f6e7 remove RCLCPP_COMPONENTS_PUBLIC in class ComponentManagerIsolated (#1843)
Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>
2021-12-09 09:41:47 -05:00
gezp
321c74c2b3 create component_container_isolated (#1781)
Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>
2021-12-07 14:24:53 -03:00
Chen Lihui
536df11ee0 Make node base sharable (#1832)
Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2021-12-06 16:32:08 -03:00
Shane Loretz
6f6e9e8ce9 Add Clock::sleep_for() (#1828)
Signed-off-by: Shane Loretz <sloretz@openrobotics.org>
2021-11-30 14:02:32 -08:00
Shane Loretz
39dad4d9a7 Synchronize rcl and std::chrono steady clocks in Clock::sleep_until (#1830)
* Synchronize RCL and std::chrono steady clocks

Signed-off-by: Shane Loretz <sloretz@openrobotics.org>

* Warn about gcc steady clock bugs

Signed-off-by: Shane Loretz <sloretz@openrobotics.org>

* Try to make warning message clearer

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2021-11-30 10:37:52 -08:00
mauropasse
87d754b219 Use rclcpp::guard_condition (#1612)
* Use rclcpp::GuardCondition

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Pass GuardCondition ptr instead of ref to remove_guard_condition

Before the api was taking a reference to a guard condition,
then getting the address of it. But if a node had expired,
we can't get the orig gc dereferencing a pointer,
nor can we get an address of an out-of-scope guard condition.

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Address PR comments

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

Co-authored-by: Mauro Passerino <mpasserino@irobot.com>
2021-11-29 12:58:47 -08:00
Abrar Rahman Protyasha
e03e98220d Call CMake function to generate version header (#1805)
Provides compile-time version information for `rclcpp`.

Signed-off-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>
2021-11-12 16:53:52 -05:00
Abrar Rahman Protyasha
f7bb88fc8f Use parantheses around logging macro parameter (#1820)
* Use parantheses around logging macro parameter

This allows the macro to expand "correctly", i.e. macro argument
expression is fully evaluated before use.

Signed-off-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>

* Remove redundant parantheses around macro param

`decltype(X)` already provides sufficient "scoping" to the macro
parameter `X`.

Signed-off-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>

* Add test case for expressions as logging param

Signed-off-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>
2021-11-11 02:12:47 -05:00
Jacob Perron
0781ea543c Remove author by request (#1818)
Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2021-11-08 23:51:05 -08:00
Jacob Perron
e0e96681d9 Update maintainers (#1817)
Adding Jacob, removing Mabel.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2021-11-05 13:40:08 -07:00
Shane Loretz
b1f31e0eaa min_forward & min_backward thresholds must not be disabled (#1815)
Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2021-11-05 08:24:58 -07:00
Shane Loretz
e2aeb1028b Re-add Clock::sleep_until (#1814)
* Revert "Revert "Add Clock::sleep_until method (#1748)" (#1793)"

This reverts commit d04319a438.

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Context, Shutdown Callback, Condition Var per call

The `Clock` doesn't have enough information to know which Context should
wake it on shutdown, so this adds a Context as an argument to
sleep_until().

Since the context is per call, the shutdown callback is also registered
per call and cannot be stored on impl_.

The condition_variable is also unique per call to reduce spurious
wakeups when multiple threads sleep on the same clock.

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Throw if until has wrong clock type

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* unnecessary newline

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Shorten line

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Fix time jump thresholds and add ROS time test

Use -1 and 1 thresholds because 0 and 0 is supposed to disable the
callbacks

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Shorten line

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* rclcpp::ok() -> context->is_valid()

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* No pre-jump handler instead of noop handler

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* If ros_time_is_active errors, let it throw

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Get time source change from callback to avoid race if ROS time toggled quickly

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Fix threshold and no  pre-jump callback

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Use RCUTILS_MS_TO_NS macro

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Explicit cast for duration to system time

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Throws at the end of docblock

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Add tests for invalid and non-global contexts

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2021-11-05 08:24:30 -07:00
Grey
94264320b4 Fix lifetime of context so it remains alive while its dependent node handles are still in use (#1754)
* Fix lifetime of context so it remains alive while its dependent node handles are still in use

Signed-off-by: Michael X. Grey <grey@openrobotics.org>

* Explicitly delete moving and assigning

Signed-off-by: Michael X. Grey <grey@openrobotics.org>

* Satisfy uncrustify

Signed-off-by: Michael X. Grey <grey@openrobotics.org>

* Fix more spacing complaints

Signed-off-by: Michael X. Grey <grey@openrobotics.org>

* Fixing style

Signed-off-by: Michael X. Grey <grey@openrobotics.org>

* Provide a safe move constructor to avoid double-allocation

Signed-off-by: Michael X. Grey <grey@openrobotics.org>

* Fix uncrustify

Signed-off-by: Michael X. Grey <grey@openrobotics.org>
2021-11-01 12:29:03 -07:00
Barry Xu
b135e89c1e Add the interface for pre-shutdown callback (#1714)
* Add the interface for pre-shutdown callback

Signed-off-by: Barry Xu <barry.xu@sony.com>
2021-10-29 17:11:39 -07:00
Abrar Rahman Protyasha
c59793618a Take message ownership from moved LoanedMessage (#1808)
* Take message ownership from moved LoanedMessage

Otherwise, since the rvalue reference passed into the move
constructor of `LoanedMessage` was not set to `nullptr`, the
underlying message would be double-free'd.

Signed-off-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>

* Add unit test for LoanedMessage move construction

Signed-off-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>

* Include <utility> header to satisfy cpplint

`std::move` was being used without including said header,
which made cpplint unhappy.

Signed-off-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>
2021-10-25 14:27:12 -04:00
Chris Lalancette
5ecc5b6c19 Suppress clang dead-store warnings in the benchmarks. (#1802)
clang static analysis complains that there are dead stores in
most of the benchmark tests, which is technically correct.
We use an idiom like:

for (auto _ : state) {
}

And never access _.  Silence clang here by doing (void)_;
all of the places this is seen.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-10-22 11:27:54 -04:00
Jacob Perron
2d7bd9f4cb Wait for publisher and subscription to match (#1777)
Fix #1775

Connext takes significantly longer for discovery to happened compared to the other RMWs.
So, waiting an arbitrary amount of time for a message to be received is brittle.

By instead waiting for the publisher and subscription to match, the tests become more robust.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2021-10-20 08:32:43 -07:00
Nikolai Morin
0fd866d201 Fix unused QoS profile for clock subscription and make ClockQoS the default (#1801)
Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>
2021-10-19 08:49:54 -07:00
Ivan Santiago Paunovic
82950f1141 13.1.0 2021-10-18 19:26:36 +00:00
Ivan Santiago Paunovic
4a343a1f23 Changelogs
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-10-18 15:10:16 -03:00
Geoffrey Biggs
a569214273 Fix dangerous std::bind capture in TimeSource implementation (#1768)
* Convert internal state into shareable structs
* Add documentation
* PIMPL the class
* Use a weak_ptr to avoid a potential dangling reference
* Comply with the rule of 5

Signed-off-by: Geoffrey Biggs <gbiggs@killbots.net>
2021-10-15 11:52:41 -04:00
Geoffrey Biggs
942b74c8bd Fix dangerous std::bind capture in ParameterEventHandler implementation (#1770)
Signed-off-by: Geoffrey Biggs <gbiggs@killbots.net>
2021-10-13 11:36:19 -03:00
Ivan Santiago Paunovic
d107a844ea Handle sigterm, in the same way we handle sigint (#1771)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-10-13 10:05:12 -03:00
Tomoya Fujita
301957515a add node_waitables_ to copy constructor. (#1799)
* add node_waitables_ to copy constructor.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* add node_time_source_ to copy constructor.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* add construction_and_destruction_sub_node for action server.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

Co-authored-by: Abrar Rahman Protyasha <abrar@openrobotics.org>
2021-10-12 18:50:00 -07:00
Jorge Perez
d04319a438 Revert "Add Clock::sleep_until method (#1748)" (#1793)
This reverts commit 81df5843f3.

Signed-off-by: Jorge Perez <jjperez@ekumenlabs.com>
2021-10-05 12:14:35 -03:00
Tomoya Fujita
d5ec258080 typo fix. (#1790)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2021-09-29 15:24:19 -04:00
Michel Hidalgo
9e445bdb91 Update forward declarations of rcl_lifecycle types (#1788)
* Include rcl_lifecycle and drop forward declarations

Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
2021-09-29 10:30:51 -04:00
William Woodall
fa3a6fa597 fixup some small things that cppcheck noticed in my editor (#1783)
* fixup some small things that cppcheck noticed in my editor

Signed-off-by: William Woodall <william@osrfoundation.org>

* fix implementation too

Signed-off-by: William Woodall <william@osrfoundation.org>
2021-09-24 15:22:17 -07:00
Emerson Knapp
81df5843f3 Add Clock::sleep_until method (#1748)
* Add Clock::sleep_until method

Handle all 3 clock types, and edge cases for shutdown and enabling/disabling ROS time

Signed-off-by: Emerson Knapp <eknapp@amazon.com>
2021-09-24 15:15:23 -04:00
Tomoya Fujita
f3a5187775 NodeGraph exposure with test cases (#1484)
* add NodeGraph::get_node_names_and_namespaces()

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* add test for NodeGraph::get_node_names_and_namespaces

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* add NodeGraph::get_client_names_and_types_by_node()

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* add test for NodeGraph::get_client_names_and_types_by_node

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* add NodeGraph::get_publisher/subscriber_names_and_types_by_node()

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* add test for NodeGraph::get_publisher/subscriber_names_and_types_by_node

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* fix comments.

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* use make_scope_exit and update comments.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* comment fix.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* minor fixes.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* add comments for enclaves.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* add URL about ROS 2 Security Enclaves.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* Deprecated `shared_ptr<MessageT>` sub callbacks

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2021-09-23 13:45:58 -07:00
livanov93
2801553d61 Improve documentation for auto declaration from overrides (#1751)
* Improve documentation for auto declaration from overrides.

Signed-off-by: voodoo <lovro.ivanov@gmail.com>

* Fix spelling.

Signed-off-by: voodoo <lovro.ivanov@gmail.com>

* Extend description.

Signed-off-by: voodoo <lovro.ivanov@gmail.com>
2021-09-13 17:36:11 -07:00
Yong-Hao Zou
001f0fb620 Replace recursion with do-while (#1765)
to avoid potential stack-overflow.

Signed-off-by: zouyonghao <yonghaoz1994@gmail.com>
2021-09-13 09:25:06 -04:00
Chris Lalancette
665e37784a Make sure to check for empty extension before accessing front. (#1764)
The documentation for std::string::front() says that calling it
on an empty string is undefined behavior.  It actually seems to
work on all platforms except Windows Debug, where it throws an
error.  Make sure to check for empty first.

We also notice that there is no reason to check the
existing_sub_namespace for empty; the rest of the code handles
that fine.  So remove that check.

Finally, we add an anonymous namespace so that these functions do
not pollute the global namespace.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-09-03 08:49:57 -04:00
Abrar Rahman Protyasha
ecb81ef2c3 Deprecate the void shared_ptr<MessageT> subscription callback signatures (#1713)
* Deprecated `shared_ptr<MessageT>` sub callbacks

Addresses #1619.

Signed-off-by: Abrar Rahman Protyasha <abrar@openrobotics.org>

* Resolve deprecated subscription callbacks in tests

Specifically, `void shared_ptr<MessageT>` subscription callbacks have
been migrated to `void shared_ptr<const MessageT>` subscription
callbacks.

This change has been performed only on the test files that do
not actually house unit tests for the `AnySubscriptionCallback` class.
For unit tests that actually target the deprecated `set` functions,
the deprecation warnings have to be avoided. This patch will be
introduced in a separate commit.

Signed-off-by: Abrar Rahman Protyasha <abrar@openrobotics.org>

* Suppress deprecation warnings in unit tests

This commit specifically introduces suppression of the deprecation
warnings produced while compiling unit tests for the
`AnySubscriptionCallback` class.

The macro mechanics to conditionally include the `deprecated` attribute
is not ideal, but the diagnostic pragma solution (`# pragma GCC
diagnostic ignored`) did not work for these unit tests, possibly because
of the way gtest is initializing the necessary `InstanceContext`
objects.

A `TODO` directive has been left to figure out a better way to address
this warning suppression.

Signed-off-by: Abrar Rahman Protyasha <abrar@openrobotics.org>

* Fix shared ptr callback in wait_for_message

Moving away from deprecated signatures.

Signed-off-by: Abrar Rahman Protyasha <abrar@openrobotics.org>

* `rclcpp_action`: Fix deprecated subscr. callbacks

Signed-off-by: Abrar Rahman Protyasha <abrar@openrobotics.org>

* `rclcpp_lifecycle`: Fix deprecated sub callbacks

Signed-off-by: Abrar Rahman Protyasha <abrar@openrobotics.org>
2021-08-26 18:33:03 -04:00
446 changed files with 45432 additions and 11304 deletions

View File

@@ -1,45 +0,0 @@
<!--
For general questions, please ask on ROS answers: https://answers.ros.org, make sure to include at least the `ros2` tag and the rosdistro version you are running, e.g. `ardent`.
For general design discussions, please post on discourse: https://discourse.ros.org/c/ng-ros
Not sure if this is the right repository? Open an issue on https://github.com/ros2/ros2/issues
For Bug report or feature requests, please fill out the relevant category below
-->
## Bug report
**Required Info:**
- Operating System:
- <!-- OS and version (e.g. Windows 10, Ubuntu 16.04...) -->
- Installation type:
- <!-- binaries or from source -->
- Version or commit hash:
- <!-- Output of git rev-parse HEAD, release version, or repos file -->
- DDS implementation:
- <!-- rmw_implementation used (e.g. Fast-RTPS, RTI Connext, etc -->
- Client library (if applicable):
- <!-- e.g. rclcpp, rclpy, or N/A -->
#### Steps to reproduce issue
<!-- Detailed instructions on how to reliably reproduce this issue http://sscce.org/
``` code that can be copy-pasted is preferred ``` -->
```
```
#### Expected behavior
#### Actual behavior
#### Additional information
<!-- If you are reporting a bug delete everything below
If you are requesting a feature deleted everything above this line -->
----
## Feature request
#### Feature description
<!-- Description in a few sentences what the feature consists of and what problem it will solve -->
#### Implementation considerations
<!-- Relevant information on how the feature could be implemented and pros and cons of the different solutions -->

View File

@@ -8,7 +8,8 @@ rclcpp provides the standard C++ API for interacting with ROS 2.
`#include "rclcpp/rclcpp.hpp"` allows use of the most common elements of the ROS 2 system.
Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) for a complete list of its main components.
The link to the latest API documentation can be found on the [rclcpp package info page](https://docs.ros.org/en/rolling/p/rclcpp).
### Examples

View File

@@ -2,6 +2,815 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30.1.5 (2026-02-09)
-------------------
* remove default: so that compiler can detect the missing case. (`#3048 <https://github.com/ros2/rclcpp/issues/3048>`_)
* use weak_ptr for rcl entities in the memory strategy. (`#2988 <https://github.com/ros2/rclcpp/issues/2988>`_)
* remove test_static_executor_entities_collector.cpp (`#3041 <https://github.com/ros2/rclcpp/issues/3041>`_)
* include the 1st spin that might throw the exception. (`#3042 <https://github.com/ros2/rclcpp/issues/3042>`_)
* print warning message on owner node if the parameter operation fails. (`#3037 <https://github.com/ros2/rclcpp/issues/3037>`_)
* fix context in wait for message wait set (`#3030 <https://github.com/ros2/rclcpp/issues/3030>`_)
* Revert "construct wait set with passed in context (`#3021 <https://github.com/ros2/rclcpp/issues/3021>`_)" (`#3028 <https://github.com/ros2/rclcpp/issues/3028>`_)
* construct wait set with passed in context (`#3021 <https://github.com/ros2/rclcpp/issues/3021>`_)
* Improve the robustness of the TopicEndpointInfo constructor (`#3013 <https://github.com/ros2/rclcpp/issues/3013>`_)
* Deprecate the shared_ptr<MessageT> subscription callback signatures (`#2975 <https://github.com/ros2/rclcpp/issues/2975>`_)
* Contributors: Barry Xu, Maurice Alexander Purnawan, Michael Carroll, Rahat Dhande, Tomoya Fujita
30.1.4 (2025-12-23)
-------------------
* Updated deprecated ament_index_cpp API (`#3011 <https://github.com/ros2/rclcpp/issues/3011>`_)
* Unified Node Interfaces: Add const version of get_node_x_interface() (`#3006 <https://github.com/ros2/rclcpp/issues/3006>`_)
* Parameter Descriptor Simplification (`#2179 <https://github.com/ros2/rclcpp/issues/2179>`_)
* ParameterEventHandler support ContentFiltering (`#2971 <https://github.com/ros2/rclcpp/issues/2971>`_)
* update policy_name_from_kind && test_qos (`#2156 <https://github.com/ros2/rclcpp/issues/2156>`_)
* Add ability to disable and enable subscription's callbacks (`#2985 <https://github.com/ros2/rclcpp/issues/2985>`_)
* Switch to isolated testing via rmw_test_fixture (`#2929 <https://github.com/ros2/rclcpp/issues/2929>`_)
* remove I/O from signal handler. (`#2986 <https://github.com/ros2/rclcpp/issues/2986>`_)
* Contributors: Alejandro Hernández Cordero, Andrianov Roman, Barry Xu, Lucas Wendland, Michael Orlov, Tomoya Fujita, fabianhirmann, yadunund
30.1.3 (2025-11-18)
-------------------
* correct test function descriptions (`#2970 <https://github.com/ros2/rclcpp/issues/2970>`_)
* add : get clients, servers info (`#2569 <https://github.com/ros2/rclcpp/issues/2569>`_)
* Fix REP url locations (`#2987 <https://github.com/ros2/rclcpp/issues/2987>`_)
* Contributors: Minju, Lee, Tim Clephas, Yuchen966
30.1.2 (2025-10-21)
-------------------
* clear handles before node destruction in test_memory_strategy. (`#2969 <https://github.com/ros2/rclcpp/issues/2969>`_)
* Added static assert asserting custom types have no overloaded operator new (`#2954 <https://github.com/ros2/rclcpp/issues/2954>`_)
* Store graph listener inside the context instead of the node graph (`#2952 <https://github.com/ros2/rclcpp/issues/2952>`_)
* Reapply "Catch the exception from rate.sleep() if the context is invalid. (`#2956 <https://github.com/ros2/rclcpp/issues/2956>`_)" (`#2963 <https://github.com/ros2/rclcpp/issues/2963>`_) (`#2964 <https://github.com/ros2/rclcpp/issues/2964>`_)
* Revert "Catch the exception from rate.sleep() if the context is invalid. (`#2956 <https://github.com/ros2/rclcpp/issues/2956>`_)" (`#2963 <https://github.com/ros2/rclcpp/issues/2963>`_)
* Catch the exception from rate.sleep() if the context is invalid. (`#2956 <https://github.com/ros2/rclcpp/issues/2956>`_)
* update Time documentation (`#2955 <https://github.com/ros2/rclcpp/issues/2955>`_)
* Contributors: Ilario A. Azzollini, Ivo Ivanov, Skyler Medeiros, Tomoya Fujita
30.1.1 (2025-09-11)
-------------------
* Removed warning (`#2949 <https://github.com/ros2/rclcpp/issues/2949>`_)
* add note about problems with spin_until_future_complete (`#2849 <https://github.com/ros2/rclcpp/issues/2849>`_)
* deprecate rclcpp::spin_some and rclcpp::spin_all (`#2848 <https://github.com/ros2/rclcpp/issues/2848>`_)
* Improve the function extract_type_identifier (`#2923 <https://github.com/ros2/rclcpp/issues/2923>`_)
* Allow for implicitly convertable loggers as well (`#2922 <https://github.com/ros2/rclcpp/issues/2922>`_)
* Contributors: Alberto Soragna, Alejandro Hernández Cordero, Barry Xu, Tim Clephas
30.1.0 (2025-07-29)
-------------------
* Fix: improve exception context for parameter_value_from (`#2917 <https://github.com/ros2/rclcpp/issues/2917>`_)
* Fix `start_type_description_service` param handling (`#2897 <https://github.com/ros2/rclcpp/issues/2897>`_)
* Add qos parameter for wait_for_message function (`#2903 <https://github.com/ros2/rclcpp/issues/2903>`_)
* Fujitatomoya/test append parameter override (`#2896 <https://github.com/ros2/rclcpp/issues/2896>`_)
* Expose `typesupport_helpers` API needed for the Rosbag2 (`#2858 <https://github.com/ros2/rclcpp/issues/2858>`_)
* Remove comment about now-removed StaticSingleThreadedExecutor (`#2893 <https://github.com/ros2/rclcpp/issues/2893>`_)
* Add overload of `append_parameter_override` (`#2891 <https://github.com/ros2/rclcpp/issues/2891>`_)
* fix: Don't deadlock if removing shutdown callbacks in a shutdown callback (`#2886 <https://github.com/ros2/rclcpp/issues/2886>`_)
* Contributors: Christophe Bedard, Janosch Machowinski, Michael Orlov, Michiel Leegwater, Patrick Roncagliolo, Sriharsha Ghanta, Tomoya Fujita
30.0.0 (2025-07-01)
-------------------
* Hand-code logging.hpp (`#2870 <https://github.com/ros2/rclcpp/issues/2870>`_)
* Adressed TODO in node_graph (`#2877 <https://github.com/ros2/rclcpp/issues/2877>`_)
* fix test_publisher_with_system_default_qos. (`#2881 <https://github.com/ros2/rclcpp/issues/2881>`_)
* Contributors: Alejandro Hernández Cordero, Chris Lalancette, Tomoya Fujita
29.6.1 (2025-06-23)
-------------------
* Fix for memory leaks in rclcpp::SerializedMessage (`#2861 <https://github.com/ros2/rclcpp/issues/2861>`_)
* Removed warning test_qos (`#2859 <https://github.com/ros2/rclcpp/issues/2859>`_)
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_)
* get_all_data_impl() does not handle null pointers properly, causing segmentation fault (`#2840 <https://github.com/ros2/rclcpp/issues/2840>`_)
* QoSInitialization::from_rmw does not validate invalid history policy values, leading to silent failures (`#2841 <https://github.com/ros2/rclcpp/issues/2841>`_)
* remove get_notify_guard_condition from NodeBaseInterface. (`#2839 <https://github.com/ros2/rclcpp/issues/2839>`_)
* Removed deprecated StaticSingleThreadedExecutor (`#2835 <https://github.com/ros2/rclcpp/issues/2835>`_)
* Removed deprecated rcpputils Path (`#2834 <https://github.com/ros2/rclcpp/issues/2834>`_)
* Add range constraints for applicable array parameters (`#2828 <https://github.com/ros2/rclcpp/issues/2828>`_)
* Update RingBufferImplementation to clear internal data. (`#2837 <https://github.com/ros2/rclcpp/issues/2837>`_)
* Removed deprecated cancel_sleep_or_wait (`#2836 <https://github.com/ros2/rclcpp/issues/2836>`_)
* Add missing 's' to 'NodeParametersInterface' in doc/comment (`#2831 <https://github.com/ros2/rclcpp/issues/2831>`_)
* subordinate node consistent behavior and update docstring. (`#2822 <https://github.com/ros2/rclcpp/issues/2822>`_)
* Contributors: Alejandro Hernández Cordero, Alex Youngs, Christophe Bedard, Michael Carlstrom, Michael Orlov, Tomoya Fujita
29.6.0 (2025-04-25)
-------------------
* throws std::invalid_argument if ParameterEvent is NULL. (`#2814 <https://github.com/ros2/rclcpp/issues/2814>`_)
* Removed clang warnings (`#2823 <https://github.com/ros2/rclcpp/issues/2823>`_)
* Contributors: Alejandro Hernández Cordero, Tomoya Fujita
29.5.0 (2025-04-18)
-------------------
* Fix a race condition (`#2819 <https://github.com/ros2/rclcpp/issues/2819>`_)
* Remove redundant typesupport check in serialization module (`#2808 <https://github.com/ros2/rclcpp/issues/2808>`_)
* Remove get_typesupport_handle implementation. (`#2806 <https://github.com/ros2/rclcpp/issues/2806>`_)
* Use NodeParameterInterface instead of /parameter_event to update "use_sim_time" (`#2378 <https://github.com/ros2/rclcpp/issues/2378>`_)
* Remove cancel_clock_executor_promise\_. (`#2797 <https://github.com/ros2/rclcpp/issues/2797>`_)
* Enable parameter update recursively only when QoS override parameters. (`#2742 <https://github.com/ros2/rclcpp/issues/2742>`_)
* Contributors: Pedro de Azeredo, Tanishq Chaudhary, Tomoya Fujita
29.4.0 (2025-04-04)
-------------------
* Removed trailing whitespace from the codebase. (`#2791 <https://github.com/ros2/rclcpp/issues/2791>`_)
* Expanded docstring of `get_rmw_qos_profile()` (`#2787 <https://github.com/ros2/rclcpp/issues/2787>`_)
* Set envars to run tests with rmw_zenoh_cpp with multicast discovery (`#2776 <https://github.com/ros2/rclcpp/issues/2776>`_)
* fix: Compilefix for clang (`#2775 <https://github.com/ros2/rclcpp/issues/2775>`_)
* add exception doc for configure_introspection. (`#2773 <https://github.com/ros2/rclcpp/issues/2773>`_)
* feat: Add ClockWaiter and ClockConditionalVariable (`#2691 <https://github.com/ros2/rclcpp/issues/2691>`_)
* doc: Added warning to not instantiate Clock directly with RCL_ROS_TIME (`#2768 <https://github.com/ros2/rclcpp/issues/2768>`_)
* Use rmw_event_type_is_supported in test_qos_event (`#2761 <https://github.com/ros2/rclcpp/issues/2761>`_)
* Support action typesupport helper (`#2750 <https://github.com/ros2/rclcpp/issues/2750>`_)
* use maybe_unused attribute for the portability. (`#2758 <https://github.com/ros2/rclcpp/issues/2758>`_)
* Executor strong reference fix (`#2745 <https://github.com/ros2/rclcpp/issues/2745>`_)
* Cleanup of https://github.com/ros2/rclcpp/pull/2683 (`#2714 <https://github.com/ros2/rclcpp/issues/2714>`_)
* Fix typo in doc section for get_service_typesupport_handle (`#2751 <https://github.com/ros2/rclcpp/issues/2751>`_)
* Test case and fix for for https://github.com/ros2/rclcpp/issues/2652 (`#2713 <https://github.com/ros2/rclcpp/issues/2713>`_)
* fix(timer): Delete node, after executor thread terminated (`#2737 <https://github.com/ros2/rclcpp/issues/2737>`_)
* update doc section for spin_xxx methods. (`#2730 <https://github.com/ros2/rclcpp/issues/2730>`_)
* fix: Expose timers used by rclcpp::Waitables (`#2699 <https://github.com/ros2/rclcpp/issues/2699>`_)
* use rmw_qos_profile_rosout_default instead of rcl. (`#2663 <https://github.com/ros2/rclcpp/issues/2663>`_)
* fix(Executor): Fixed entities not beeing executed after just beeing added (`#2724 <https://github.com/ros2/rclcpp/issues/2724>`_)
* fix: make the loop condition align with the description (`#2726 <https://github.com/ros2/rclcpp/issues/2726>`_)
* Collect log messages from rcl, and reset. (`#2720 <https://github.com/ros2/rclcpp/issues/2720>`_)
* Contributors: Abhishek Kashyap, Alejandro Hernández Cordero, Barry Xu, Janosch Machowinski, Leander Stephen D'Souza, Tomoya Fujita, Yuyuan Yuan
29.3.0 (2024-12-20)
-------------------
* Fix transient local IPC publish (`#2708 <https://github.com/ros2/rclcpp/issues/2708>`_)
* apply actual QoS from rmw to the IPC publisher. (`#2707 <https://github.com/ros2/rclcpp/issues/2707>`_)
* Adding in topic name to logging on IPC issues (`#2706 <https://github.com/ros2/rclcpp/issues/2706>`_)
* fix TestTimeSource.ROS_time_valid_attach_detach. (`#2700 <https://github.com/ros2/rclcpp/issues/2700>`_)
* Update docstring for `rclcpp::Node::now()` (`#2696 <https://github.com/ros2/rclcpp/issues/2696>`_)
* Re-enable executor test on rmw_connextdds. (`#2693 <https://github.com/ros2/rclcpp/issues/2693>`_)
* Fix warnings on Windows. (`#2692 <https://github.com/ros2/rclcpp/issues/2692>`_)
* Omnibus fixes for running tests with Connext. (`#2684 <https://github.com/ros2/rclcpp/issues/2684>`_)
* fix(Executor): Fix segfault if callback group is deleted during rmw_wait (`#2683 <https://github.com/ros2/rclcpp/issues/2683>`_)
* Contributors: Chris Lalancette, Jeffery Hsu, Patrick Roncagliolo, Steve Macenski, Tomoya Fujita, jmachowinski
29.2.0 (2024-11-25)
-------------------
* accept custom allocator for LoanedMessage. (`#2672 <https://github.com/ros2/rclcpp/issues/2672>`_)
* Contributors: Tomoya Fujita
29.1.0 (2024-11-20)
-------------------
* a couple of typo fixes in doc section for LoanedMessage. (`#2676 <https://github.com/ros2/rclcpp/issues/2676>`_)
* Make sure callback_end tracepoint is triggered in AnyServiceCallback (`#2670 <https://github.com/ros2/rclcpp/issues/2670>`_)
* Correct the incorrect comments in generic_client.hpp (`#2662 <https://github.com/ros2/rclcpp/issues/2662>`_)
* Fix NodeOptions assignment operator (`#2656 <https://github.com/ros2/rclcpp/issues/2656>`_)
* set QoS History KEEP_ALL explicitly for statistics publisher. (`#2650 <https://github.com/ros2/rclcpp/issues/2650>`_)
* Fix test_intra_process_manager.cpp with rmw_zenoh_cpp (`#2653 <https://github.com/ros2/rclcpp/issues/2653>`_)
* Fixed test_events_executors in zenoh (`#2643 <https://github.com/ros2/rclcpp/issues/2643>`_)
* rmw_fastrtps supports service event gid uniqueness test. (`#2638 <https://github.com/ros2/rclcpp/issues/2638>`_)
* print warning if event callback is not supported instead of passing exception. (`#2648 <https://github.com/ros2/rclcpp/issues/2648>`_)
* Implement callback support of async_send_request for service generic client (`#2614 <https://github.com/ros2/rclcpp/issues/2614>`_)
* Contributors: Alejandro Hernández Cordero, Barry Xu, Chris Lalancette, Christophe Bedard, Romain DESILLE, Tomoya Fujita
29.0.0 (2024-10-03)
-------------------
* Fixed test qos rmw zenoh (`#2639 <https://github.com/ros2/rclcpp/issues/2639>`_)
* verify client gid uniqueness for a single service event. (`#2636 <https://github.com/ros2/rclcpp/issues/2636>`_)
* Skip some tests in test_qos_event and run others with event types supported by rmw_zenoh (`#2626 <https://github.com/ros2/rclcpp/issues/2626>`_)
* Shutdown the context before context's destructor is invoked in tests (`#2633 <https://github.com/ros2/rclcpp/issues/2633>`_)
* Skip rmw zenoh content filtering tests (`#2627 <https://github.com/ros2/rclcpp/issues/2627>`_)
* Use InvalidServiceTypeError for unavailable service type in GenericClient (`#2629 <https://github.com/ros2/rclcpp/issues/2629>`_)
* Implement generic service (`#2617 <https://github.com/ros2/rclcpp/issues/2617>`_)
* fix events-executor warm-up bug and add unit-tests (`#2591 <https://github.com/ros2/rclcpp/issues/2591>`_)
* remove unnecessary gtest-skip in test_executors (`#2600 <https://github.com/ros2/rclcpp/issues/2600>`_)
* Correct node name in service test code (`#2615 <https://github.com/ros2/rclcpp/issues/2615>`_)
* Minor naming fixes for ParameterValue to_string() function (`#2609 <https://github.com/ros2/rclcpp/issues/2609>`_)
* Removed clang warnings (`#2605 <https://github.com/ros2/rclcpp/issues/2605>`_)
* Fix a couple of issues in the documentation. (`#2608 <https://github.com/ros2/rclcpp/issues/2608>`_)
* deprecate the static single threaded executor (`#2598 <https://github.com/ros2/rclcpp/issues/2598>`_)
* Fix name of ParameterEventHandler class in doc (`#2604 <https://github.com/ros2/rclcpp/issues/2604>`_)
* subscriber_statistics_collectors\_ should be protected by mutex. (`#2592 <https://github.com/ros2/rclcpp/issues/2592>`_)
* Fix bug in timers lifecycle for events executor (`#2586 <https://github.com/ros2/rclcpp/issues/2586>`_)
* fix rclcpp/test/rclcpp/CMakeLists.txt to check for the correct targets existance (`#2596 <https://github.com/ros2/rclcpp/issues/2596>`_)
* Shut down context during init if logging config fails (`#2594 <https://github.com/ros2/rclcpp/issues/2594>`_)
* Make more of the Waitable API abstract (`#2593 <https://github.com/ros2/rclcpp/issues/2593>`_)
* Contributors: Alberto Soragna, Alejandro Hernández Cordero, Alexis Pojomovsky, Barry Xu, Chris Lalancette, Christophe Bedard, Kang, Hsin-Yi, Tomoya Fujita
28.3.3 (2024-07-29)
-------------------
* Only compile the tests once. (`#2590 <https://github.com/ros2/rclcpp/issues/2590>`_)
* Contributors: Chris Lalancette
28.3.2 (2024-07-24)
-------------------
* Updated rcpputils path API (`#2579 <https://github.com/ros2/rclcpp/issues/2579>`_)
* Make the subscriber_triggered_to_receive_message test more reliable. (`#2584 <https://github.com/ros2/rclcpp/issues/2584>`_)
* Make the subscriber_triggered_to_receive_message test more reliable.
In the current code, inside of the timer we create the subscription
and the publisher, publish immediately, and expect the subscription
to get it immediately. But it may be the case that discovery
hasn't even happened between the publisher and the subscription
by the time the publish call happens.
To make this more reliable, create the subscription and publish *before*
we ever create and spin on the timer. This at least gives 100
milliseconds for discovery to happen. That may not be quite enough
to make this reliable on all platforms, but in my local testing this
helps a lot. Prior to this change I can make this fail one out of 10
times, and after the change I've run 100 times with no failures.
* Have the EventsExecutor use more common code (`#2570 <https://github.com/ros2/rclcpp/issues/2570>`_)
* move notify waitable setup to its own function
* move mutex lock to retrieve_entity utility
* use entities_need_rebuild\_ atomic bool in events-executors
* remove duplicated set_on_ready_callback for notify_waitable
* use mutex from base class rather than a new recursive mutex
* use current_collection\_ member in events-executor
* delay adding notify waitable to collection
* postpone clearing the current collection
* commonize notify waitable and collection
* commonize add/remove node/cbg methods
* fix linter errors
---------
* Removed deprecated methods and classes (`#2575 <https://github.com/ros2/rclcpp/issues/2575>`_)
* Release ownership of entities after spinning cancelled (`#2556 <https://github.com/ros2/rclcpp/issues/2556>`_)
* Release ownership of entities after spinning cancelled
* Move release action to every exit point in different spin functions
* Move wait_result\_.reset() before setting spinning to false
* Update test code
* Move test code to test_executors.cpp
---------
* Split test_executors.cpp even further. (`#2572 <https://github.com/ros2/rclcpp/issues/2572>`_)
That's because it is too large for Windows Debug to compile,
so split into smaller bits.
Even with this split, the file is too big; that's likely
because we are using TYPED_TEST here, which generates multiple
symbols per test case. To deal with this, without further
breaking up the file, also add in the /bigobj flag when
compiling on Windows Debug.
* avoid adding notify waitable twice to events-executor collection (`#2564 <https://github.com/ros2/rclcpp/issues/2564>`_)
* avoid adding notify waitable twice to events-executor entities collection
* remove redundant mutex lock
---------
* Contributors: Alberto Soragna, Alejandro Hernández Cordero, Barry Xu, Chris Lalancette
28.3.1 (2024-06-25)
-------------------
* Remove unnecessary msg includes in tests (`#2566 <https://github.com/ros2/rclcpp/issues/2566>`_)
* Fix copy-paste errors in function docs (`#2565 <https://github.com/ros2/rclcpp/issues/2565>`_)
* Fix typo in function doc (`#2563 <https://github.com/ros2/rclcpp/issues/2563>`_)
* Contributors: Christophe Bedard
28.3.0 (2024-06-17)
-------------------
* Add test creating two content filter topics with the same topic name (`#2546 <https://github.com/ros2/rclcpp/issues/2546>`_) (`#2549 <https://github.com/ros2/rclcpp/issues/2549>`_)
* add impl pointer for ExecutorOptions (`#2523 <https://github.com/ros2/rclcpp/issues/2523>`_)
* Fixup Executor::spin_all() regression fix (`#2517 <https://github.com/ros2/rclcpp/issues/2517>`_)
* Add 'mimick' label to tests which use Mimick (`#2516 <https://github.com/ros2/rclcpp/issues/2516>`_)
* Contributors: Alejandro Hernández Cordero, Scott K Logan, William Woodall
28.2.0 (2024-04-26)
-------------------
* Check for negative time in rclcpp::Time(int64_t nanoseconds, ...) constructor (`#2510 <https://github.com/ros2/rclcpp/issues/2510>`_)
* Revise the description of service configure_introspection() (`#2511 <https://github.com/ros2/rclcpp/issues/2511>`_)
* Contributors: Barry Xu, Sharmin Ramli
28.1.0 (2024-04-16)
-------------------
* Remove references to index.ros.org. (`#2504 <https://github.com/ros2/rclcpp/issues/2504>`_)
* Reduce overhead for inheriting from rclcpp::Executor when base functionality is not reused (`#2506 <https://github.com/ros2/rclcpp/issues/2506>`_)
* Contributors: Chris Lalancette, William Woodall, jmachowinski
28.0.1 (2024-04-16)
-------------------
* [wjwwood] Updated "Data race fixes" (`#2500 <https://github.com/ros2/rclcpp/issues/2500>`_)
* Fix callback group logic in executor
* fix: Fixed unnecessary copy of wait_set
* fix(executor): Fixed race conditions with rebuild of wait_sets
Before this change, the rebuild of wait set would be triggered
after the wait set was waken up. With bad timing, this could
lead to the rebuild not happening with multi threaded executor.
* fix(Executor): Fixed lost of entities rebuild request
* chore: Added assert for not set callback_group in execute_any_executable
* Add test for cbg getting reset
Co-authored-by: Janosch Machowinski <j.machowinski@nospam.org>
* chore: renamed test cases to snake_case
* style
* fixup test to avoid polling and short timeouts
* fix: Use correct notify_waitable\_ instance
* fix(StaticSingleThreadedExecutor): Added missing special case handling for current_notify_waitable\_
* fix(TestCallbackGroup): Fixed test after change to timers
---------
Co-authored-by: Janosch Machowinski <j.machowinski@cellumation.com>
Co-authored-by: Michael Carroll <mjcarroll@intrinsic.ai>
Co-authored-by: Janosch Machowinski <j.machowinski@nospam.org>
* fixup var names to snake case (`#2501 <https://github.com/ros2/rclcpp/issues/2501>`_)
* Added optional TimerInfo to timer callback (`#2343 <https://github.com/ros2/rclcpp/issues/2343>`_)
Co-authored-by: Alexis Tsogias <a.tsogias@cellumation.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
* Fix uninitialized memory in test (`#2498 <https://github.com/ros2/rclcpp/issues/2498>`_)
When I added in the tests for large messages, I made a mistake and reserved space in the strings, but didn't actually expand it. Thus, we were writing into uninitialized memory. Fix this by just using the correct constructor for string, which will allocate and initialize the memory properly.
* Ensure waitables handle guard condition retriggering (`#2483 <https://github.com/ros2/rclcpp/issues/2483>`_)
Co-authored-by: Michael Carroll <mjcarroll@intrinsic.ai>
* fix: init concatenated_vector with begin() & end() (`#2492 <https://github.com/ros2/rclcpp/issues/2492>`_)
* this commit will fix the warning [-Wstringop-overflow=] `#2461 <https://github.com/ros2/rclcpp/issues/2461>`_
* Use the same context for the specified node in rclcpp::spin functions (`#2433 <https://github.com/ros2/rclcpp/issues/2433>`_)
* Use the same conext for the specified node in rclcpp::spin_xx functions
* Add test for spinning with non-default-context
* Format code
---------
* Disable compare-function-pointers in test_utilities (`#2489 <https://github.com/ros2/rclcpp/issues/2489>`_)
* address ambiguous auto variable. (`#2481 <https://github.com/ros2/rclcpp/issues/2481>`_)
* Increase the cppcheck timeout to 1200 seconds (`#2484 <https://github.com/ros2/rclcpp/issues/2484>`_)
* Removed test_timers_manager clang warning (`#2479 <https://github.com/ros2/rclcpp/issues/2479>`_)
* Flaky timer test fix (`#2469 <https://github.com/ros2/rclcpp/issues/2469>`_)
* fix(time_source): Fixed possible race condition
* fix(test_executors_time_cancel_behaviour): Fixed multiple race conditions
---------
Co-authored-by: Janosch Machowinski <j.machowinski@nospam.org>
* Add tracepoint for generic publisher/subscriber (`#2448 <https://github.com/ros2/rclcpp/issues/2448>`_)
* update rclcpp::Waitable API to use references and const (`#2467 <https://github.com/ros2/rclcpp/issues/2467>`_)
* Utilize rclcpp::WaitSet as part of the executors (`#2142 <https://github.com/ros2/rclcpp/issues/2142>`_)
* Deprecate callback_group call taking context
* Add base executor objects that can be used by implementors
* Template common operations
* Address reviewer feedback:
* Add callback to EntitiesCollector constructor
* Make function to check automatically added callback groups take a list
* Lint
* Address reviewer feedback and fix templates
* Lint and docs
* Make executor own the notify waitable
* Add pending queue to collector, remove from waitable
Also change node's get_guard_condition to return shared_ptr
* Change interrupt guard condition to shared_ptr
Check if guard condition is valid before adding it to the waitable
* Lint and docs
* Utilize rclcpp::WaitSet as part of the executors
* Don't exchange atomic twice
* Fix add_node and add more tests
* Make get_notify_guard_condition follow API tick-tock
* Improve callback group tick-tocking
* Don't lock twice
* Address reviewer feedback
* Add thread safety annotations and make locks consistent
* @wip
* Reset callback groups for multithreaded executor
* Avoid many small function calls when building executables
* Re-trigger guard condition if buffer has data
* Address reviewer feedback
* Trace points
* Remove tracepoints
* Reducing diff
* Reduce diff
* Uncrustify
* Restore tests
* Back to weak_ptr and reduce test time
* reduce diff and lint
* Restore static single threaded tests that weren't working before
* Restore more tests
* Fix multithreaded test
* Fix assert
* Fix constructor test
* Change ready_executables signature back
* Don't enforce removing callback groups before nodes
* Remove the "add_valid_node" API
* Only notify if the trigger condition is valid
* Only trigger if valid and needed
* Fix spin_some/spin_all implementation
* Restore single threaded executor
* Picking ABI-incompatible executor changes
* Add PIMPL
* Additional waitset prune
* Fix bad merge
* Expand test timeout
* Introduce method to clear expired entities from a collection
* Make sure to call remove_expired_entities().
* Prune queued work when callback group is removed
* Prune subscriptions from dynamic storage
* Styles fixes.
* Re-trigger guard conditions
* Condense to just use watiable.take_data
* Lint
* Address reviewer comments (nits)
* Lock mutex when copying
* Refactors to static single threaded based on reviewers
* More small refactoring
* Lint
* Lint
* Add ready executable accessors to WaitResult
* Make use of accessors from wait_set
* Fix tests
* Fix more tests
* Tidy up single threaded executor implementation
* Don't null out timer, rely on call
* change how timers are checked from wait result in executors
* peak -> peek
* fix bug in next_waitable logic
* fix bug in StaticSTE that broke the add callback groups to executor tests
* style
---------
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
Co-authored-by: William Woodall <william@osrfoundation.org>
* fix flakiness in TestTimersManager unit-test (`#2468 <https://github.com/ros2/rclcpp/issues/2468>`_)
the previous version of the test was relying on the assumption that a timer with 1ms period gets called at least 6 times if the main thread waits 15ms. this is true most of the times, but it's not guaranteed, especially when running the test on windows CI servers. the new version of the test makes no assumptions on how much time it takes for the timers manager to invoke the timers, but rather focuses on ensuring that they are called the right amount of times, which is what's important for the purpose of the test
* Contributors: Alberto Soragna, Alejandro Hernández Cordero, Chris Lalancette, Homalozoa X, Kotaro Yoshimoto, Michael Carroll, Tomoya Fujita, William Woodall, h-suzuki-isp, jmachowinski
28.0.0 (2024-03-28)
-------------------
* fix spin_some_max_duration unit-test for events-executor (`#2465 <https://github.com/ros2/rclcpp/issues/2465>`_)
* refactor and improve the parameterized spin_some tests for executors (`#2460 <https://github.com/ros2/rclcpp/issues/2460>`_)
* refactor and improve the spin_some parameterized tests for executors
* disable spin_some_max_duration for the StaticSingleThreadedExecutor and EventsExecutor
* fixup and clarify the docstring for Executor::spin_some()
* style
* review comments
---------
* enable simulation clock for timer canceling test. (`#2458 <https://github.com/ros2/rclcpp/issues/2458>`_)
* enable simulation clock for timer canceling test.
* move MainExecutorTypes to test_executors_timer_cancel_behavior.cpp.
---------
* Revert "relax the test simulation rate for timer canceling tests. (`#2453 <https://github.com/ros2/rclcpp/issues/2453>`_)" (`#2456 <https://github.com/ros2/rclcpp/issues/2456>`_)
This reverts commit 1c350d0d7fb9c7158e0a39057112486ddbd38e9a.
* relax the test simulation rate for timer canceling tests. (`#2453 <https://github.com/ros2/rclcpp/issues/2453>`_)
* Fix TypeAdapted publishing with large messages. (`#2443 <https://github.com/ros2/rclcpp/issues/2443>`_)
Mostly by ensuring we aren't attempting to store
large messages on the stack. Also add in tests.
I verified that before these changes, the tests failed,
while after them they succeed.
* Implement generic client (`#2358 <https://github.com/ros2/rclcpp/issues/2358>`_)
* Implement generic client
* Fix the incorrect parameter declaration
* Deleted copy constructor and assignment for FutureAndRequestId
* Update codes after rebase
* Address review comments
* Address review comments from iuhilnehc-ynos
* Correct an error in a description
* Fix window build errors
* Address review comments from William
* Add doc strings to create_generic_client
---------
* Rule of five: implement move operators (`#2425 <https://github.com/ros2/rclcpp/issues/2425>`_)
* Various cleanups to deal with uncrustify 0.78. (`#2439 <https://github.com/ros2/rclcpp/issues/2439>`_)
These should also work with uncrustify 0.72.
* Remove the set_deprecated signatures in any_subscription_callback. (`#2431 <https://github.com/ros2/rclcpp/issues/2431>`_)
These have been deprecated since April 2021, so it is safe
to remove them now.
* fix doxygen syntax for NodeInterfaces (`#2428 <https://github.com/ros2/rclcpp/issues/2428>`_)
* Set hints to find the python version we actually want. (`#2426 <https://github.com/ros2/rclcpp/issues/2426>`_)
The comment in the commit explains the reasoning behind it.
* Update quality declaration documents (`#2427 <https://github.com/ros2/rclcpp/issues/2427>`_)
* feat: add/minus for msg::Time and rclcpp::Duration (`#2419 <https://github.com/ros2/rclcpp/issues/2419>`_)
* feat: add/minus for msg::Time and rclcpp::Duration
* Contributors: Alberto Soragna, Barry Xu, Chris Lalancette, Christophe Bedard, HuaTsai, Jonas Otto, Tim Clephas, Tomoya Fujita, William Woodall
27.0.0 (2024-02-07)
-------------------
* Split test_executors up into smaller chunks. (`#2421 <https://github.com/ros2/rclcpp/issues/2421>`_)
* [events executor] - Fix Behavior with Timer Cancel (`#2375 <https://github.com/ros2/rclcpp/issues/2375>`_)
* Removed deprecated header (`#2413 <https://github.com/ros2/rclcpp/issues/2413>`_)
* Make sure to mark RingBuffer methods as 'override'. (`#2410 <https://github.com/ros2/rclcpp/issues/2410>`_)
* Contributors: Alejandro Hernández Cordero, Chris Lalancette, Matt Condino
26.0.0 (2024-01-24)
-------------------
* Increase the cppcheck timeout to 600 seconds. (`#2409 <https://github.com/ros2/rclcpp/issues/2409>`_)
* Add transient local durability support to publisher and subscriptions when using intra-process communication (`#2303 <https://github.com/ros2/rclcpp/issues/2303>`_)
* Stop storing the context in the guard condition. (`#2400 <https://github.com/ros2/rclcpp/issues/2400>`_)
* Contributors: Chris Lalancette, Jeffery Hsu
25.0.0 (2023-12-26)
-------------------
* Updated GenericSubscription to AnySubscriptionCallback (`#1928 <https://github.com/ros2/rclcpp/issues/1928>`_)
* make type support helper supported for service (`#2209 <https://github.com/ros2/rclcpp/issues/2209>`_)
* Adding QoS to subscription options (`#2323 <https://github.com/ros2/rclcpp/issues/2323>`_)
* Switch to target_link_libraries. (`#2374 <https://github.com/ros2/rclcpp/issues/2374>`_)
* aligh with rcl that a rosout publisher of a node might not exist (`#2357 <https://github.com/ros2/rclcpp/issues/2357>`_)
* Fix data race in EventHandlerBase (`#2349 <https://github.com/ros2/rclcpp/issues/2349>`_)
* Support users holding onto shared pointers in the message memory pool (`#2336 <https://github.com/ros2/rclcpp/issues/2336>`_)
* Contributors: Chen Lihui, Chris Lalancette, DensoADAS, Lucas Wendland, mauropasse
24.0.0 (2023-11-06)
-------------------
* fix (signal_handler.hpp): spelling (`#2356 <https://github.com/ros2/rclcpp/issues/2356>`_)
* Updates to not use std::move in some places. (`#2353 <https://github.com/ros2/rclcpp/issues/2353>`_)
* rclcpp::Time::max() clock type support. (`#2352 <https://github.com/ros2/rclcpp/issues/2352>`_)
* Serialized Messages with Topic Statistics (`#2274 <https://github.com/ros2/rclcpp/issues/2274>`_)
* Add a custom deleter when constructing rcl_service_t (`#2351 <https://github.com/ros2/rclcpp/issues/2351>`_)
* Disable the loaned messages inside the executor. (`#2335 <https://github.com/ros2/rclcpp/issues/2335>`_)
* Use message_info in SubscriptionTopicStatistics instead of typed message (`#2337 <https://github.com/ros2/rclcpp/issues/2337>`_)
* Add missing 'enable_rosout' comments (`#2345 <https://github.com/ros2/rclcpp/issues/2345>`_)
* Adjust rclcpp usage of type description service (`#2344 <https://github.com/ros2/rclcpp/issues/2344>`_)
* address rate related flaky tests. (`#2329 <https://github.com/ros2/rclcpp/issues/2329>`_)
* Fixes pointed out by the clang analyzer. (`#2339 <https://github.com/ros2/rclcpp/issues/2339>`_)
* Remove useless ROSRate class (`#2326 <https://github.com/ros2/rclcpp/issues/2326>`_)
* Contributors: Alexey Merzlyakov, Chris Lalancette, Jiaqi Li, Lucas Wendland, Michael Carroll, Michael Orlov, Tomoya Fujita, Zard-C
23.2.0 (2023-10-09)
-------------------
* add clients & services count (`#2072 <https://github.com/ros2/rclcpp/issues/2072>`_)
* remove invalid sized allocation test for SerializedMessage. (`#2330 <https://github.com/ros2/rclcpp/issues/2330>`_)
* Adding API to copy all parameters from one node to another (`#2304 <https://github.com/ros2/rclcpp/issues/2304>`_)
* Contributors: Minju, Lee, Steve Macenski, Tomoya Fujita
23.1.0 (2023-10-04)
-------------------
* Add locking to protect the TimeSource::NodeState::node_base\_ (`#2320 <https://github.com/ros2/rclcpp/issues/2320>`_)
* Update SignalHandler get_global_signal_handler to avoid complex types in static memory (`#2316 <https://github.com/ros2/rclcpp/issues/2316>`_)
* Removing Old Connext Tests (`#2313 <https://github.com/ros2/rclcpp/issues/2313>`_)
* Documentation for list_parameters (`#2315 <https://github.com/ros2/rclcpp/issues/2315>`_)
* Decouple rosout publisher init from node init. (`#2174 <https://github.com/ros2/rclcpp/issues/2174>`_)
* fix the depth to relative in list_parameters (`#2300 <https://github.com/ros2/rclcpp/issues/2300>`_)
* Contributors: Chris Lalancette, Lucas Wendland, Minju, Lee, Tomoya Fujita, Tully Foote
23.0.0 (2023-09-08)
-------------------
* Fix the return type of Rate::period. (`#2301 <https://github.com/ros2/rclcpp/issues/2301>`_)
* Update API docs links in package READMEs (`#2302 <https://github.com/ros2/rclcpp/issues/2302>`_)
* Cleanup flaky timers_manager tests. (`#2299 <https://github.com/ros2/rclcpp/issues/2299>`_)
* Contributors: Chris Lalancette, Christophe Bedard
22.2.0 (2023-09-07)
-------------------
* Topic correct typeadapter deduction (`#2294 <https://github.com/ros2/rclcpp/issues/2294>`_)
* Fix C++20 allocator construct deprecation (`#2292 <https://github.com/ros2/rclcpp/issues/2292>`_)
* Make Rate to select the clock to work with (`#2123 <https://github.com/ros2/rclcpp/issues/2123>`_)
* Correct the position of a comment. (`#2290 <https://github.com/ros2/rclcpp/issues/2290>`_)
* Remove unnecessary lambda captures in the tests. (`#2289 <https://github.com/ros2/rclcpp/issues/2289>`_)
* Add rcl_logging_interface as an explicit dependency. (`#2284 <https://github.com/ros2/rclcpp/issues/2284>`_)
* Revamp list_parameters to be more efficient and easier to read. (`#2282 <https://github.com/ros2/rclcpp/issues/2282>`_)
* Contributors: AiVerisimilitude, Alexey Merzlyakov, Chen Lihui, Chris Lalancette, Jiaqi Li
22.1.0 (2023-08-21)
-------------------
* Do not crash Executor when send_response fails due to client failure. (`#2276 <https://github.com/ros2/rclcpp/issues/2276>`_)
* Adding Custom Unknown Type Error (`#2272 <https://github.com/ros2/rclcpp/issues/2272>`_)
* Add a pimpl inside rclcpp::Node for future distro backports (`#2228 <https://github.com/ros2/rclcpp/issues/2228>`_)
* Remove an unused variable from the events executor tests. (`#2270 <https://github.com/ros2/rclcpp/issues/2270>`_)
* Add spin_all shortcut (`#2246 <https://github.com/ros2/rclcpp/issues/2246>`_)
* Adding Missing Group Exceptions (`#2256 <https://github.com/ros2/rclcpp/issues/2256>`_)
* Change associated clocks storage to unordered_set (`#2257 <https://github.com/ros2/rclcpp/issues/2257>`_)
* associated clocks should be protected by mutex. (`#2255 <https://github.com/ros2/rclcpp/issues/2255>`_)
* Instrument loaned message publication code path (`#2240 <https://github.com/ros2/rclcpp/issues/2240>`_)
* Contributors: Chris Lalancette, Christophe Bedard, Emerson Knapp, Luca Della Vedova, Lucas Wendland, Tomoya Fujita, Tony Najjar
22.0.0 (2023-07-11)
-------------------
* Implement get_node_type_descriptions_interface for lifecyclenode and add smoke test for it (`#2237 <https://github.com/ros2/rclcpp/issues/2237>`_)
* Add new node interface TypeDescriptionsInterface to provide GetTypeDescription service (`#2224 <https://github.com/ros2/rclcpp/issues/2224>`_)
* Move always_false_v to detail namespace (`#2232 <https://github.com/ros2/rclcpp/issues/2232>`_)
* Revamp the test_subscription.cpp tests. (`#2227 <https://github.com/ros2/rclcpp/issues/2227>`_)
* warning: comparison of integer expressions of different signedness (`#2219 <https://github.com/ros2/rclcpp/issues/2219>`_)
* Modifies timers API to select autostart state (`#2005 <https://github.com/ros2/rclcpp/issues/2005>`_)
* Enable callback group tests for connextdds (`#2182 <https://github.com/ros2/rclcpp/issues/2182>`_)
* Contributors: Chris Lalancette, Christopher Wecht, Eloy Briceno, Emerson Knapp, Nathan Wiebe Neufeldt, Tomoya Fujita
21.3.0 (2023-06-12)
-------------------
* Fix up misspellings of "receive". (`#2208 <https://github.com/ros2/rclcpp/issues/2208>`_)
* Remove flaky stressAddRemoveNode test (`#2206 <https://github.com/ros2/rclcpp/issues/2206>`_)
* Use TRACETOOLS\_ prefix for tracepoint-related macros (`#2162 <https://github.com/ros2/rclcpp/issues/2162>`_)
* Contributors: Chris Lalancette, Christophe Bedard, Michael Carroll
21.2.0 (2023-06-07)
-------------------
* remove nolint since ament_cpplint updated for the c++17 header (`#2198 <https://github.com/ros2/rclcpp/issues/2198>`_)
* Feature/available capacity of ipm (`#2173 <https://github.com/ros2/rclcpp/issues/2173>`_)
* add mutex to protect events_executor current entity collection (`#2187 <https://github.com/ros2/rclcpp/issues/2187>`_)
* Declare rclcpp callbacks before the rcl entities (`#2024 <https://github.com/ros2/rclcpp/issues/2024>`_)
* Contributors: Alberto Soragna, Chen Lihui, DensoADAS, mauropasse
21.1.1 (2023-05-11)
-------------------
* Fix race condition in events-executor (`#2177 <https://github.com/ros2/rclcpp/issues/2177>`_)
* Add missing stdexcept include (`#2186 <https://github.com/ros2/rclcpp/issues/2186>`_)
* Fix a format-security warning when building with clang (`#2171 <https://github.com/ros2/rclcpp/issues/2171>`_)
* Fix delivered message kind (`#2175 <https://github.com/ros2/rclcpp/issues/2175>`_)
* Contributors: Alberto Soragna, Chris Lalancette, methylDragon, Øystein Sture
21.1.0 (2023-04-27)
-------------------
21.0.0 (2023-04-18)
-------------------
* Add support for logging service. (`#2122 <https://github.com/ros2/rclcpp/issues/2122>`_)
* Picking ABI-incompatible executor changes (`#2170 <https://github.com/ros2/rclcpp/issues/2170>`_)
* add events-executor and timers-manager in rclcpp (`#2155 <https://github.com/ros2/rclcpp/issues/2155>`_)
* Create common structures for executors to use (`#2143 <https://github.com/ros2/rclcpp/issues/2143>`_)
* Implement deliver message kind (`#2168 <https://github.com/ros2/rclcpp/issues/2168>`_)
* Contributors: Alberto Soragna, Lei Liu, Michael Carroll, methylDragon
20.0.0 (2023-04-13)
-------------------
* applied tracepoints for ring_buffer (`#2091 <https://github.com/ros2/rclcpp/issues/2091>`_)
* Dynamic Subscription (REP-2011 Subset): Stubs for rclcpp (`#2165 <https://github.com/ros2/rclcpp/issues/2165>`_)
* Add type_hash to cpp TopicEndpointInfo (`#2137 <https://github.com/ros2/rclcpp/issues/2137>`_)
* Trigger the intraprocess guard condition with data (`#2164 <https://github.com/ros2/rclcpp/issues/2164>`_)
* Minor grammar fix (`#2149 <https://github.com/ros2/rclcpp/issues/2149>`_)
* Fix unnecessary allocations in executor.cpp (`#2135 <https://github.com/ros2/rclcpp/issues/2135>`_)
* add Logger::get_effective_level(). (`#2141 <https://github.com/ros2/rclcpp/issues/2141>`_)
* Remove deprecated header (`#2139 <https://github.com/ros2/rclcpp/issues/2139>`_)
* Implement matched event (`#2105 <https://github.com/ros2/rclcpp/issues/2105>`_)
* use allocator via init_options argument. (`#2129 <https://github.com/ros2/rclcpp/issues/2129>`_)
* Fixes to silence some clang warnings. (`#2127 <https://github.com/ros2/rclcpp/issues/2127>`_)
* Documentation improvements on the executor (`#2125 <https://github.com/ros2/rclcpp/issues/2125>`_)
* Avoid losing waitable handles while using MultiThreadedExecutor (`#2109 <https://github.com/ros2/rclcpp/issues/2109>`_)
* Hook up the incompatible type event inside of rclcpp (`#2069 <https://github.com/ros2/rclcpp/issues/2069>`_)
* Update all rclcpp packages to C++17. (`#2121 <https://github.com/ros2/rclcpp/issues/2121>`_)
* Fix clang warning: bugprone-use-after-move (`#2116 <https://github.com/ros2/rclcpp/issues/2116>`_)
* Contributors: Barry Xu, Chris Lalancette, Christopher Wecht, Emerson Knapp, Michael Carroll, Tomoya Fujita, Yadu, mauropasse, methylDragon, ymski
19.3.0 (2023-03-01)
-------------------
* Fix memory leak in tracetools::get_symbol() (`#2104 <https://github.com/ros2/rclcpp/issues/2104>`_)
* Service introspection (`#1985 <https://github.com/ros2/rclcpp/issues/1985>`_)
* Allow publishing borrowed messages with intra-process enabled (`#2108 <https://github.com/ros2/rclcpp/issues/2108>`_)
* to fix flaky test about TestTimeSource.callbacks (`#2111 <https://github.com/ros2/rclcpp/issues/2111>`_)
* Contributors: Brian, Chen Lihui, Christophe Bedard, Miguel Company
19.2.0 (2023-02-24)
-------------------
* to create a sublogger while getting child of Logger (`#1717 <https://github.com/ros2/rclcpp/issues/1717>`_)
* Fix documentation of Context class (`#2107 <https://github.com/ros2/rclcpp/issues/2107>`_)
* fixes for rmw callbacks in qos_event class (`#2102 <https://github.com/ros2/rclcpp/issues/2102>`_)
* Contributors: Alberto Soragna, Chen Lihui, Silvio Traversaro
19.1.0 (2023-02-14)
-------------------
* Add support for timers on reset callback (`#1979 <https://github.com/ros2/rclcpp/issues/1979>`_)
* Topic node guard condition in executor (`#2074 <https://github.com/ros2/rclcpp/issues/2074>`_)
* Fix bug on the disorder of calling shutdown callback (`#2097 <https://github.com/ros2/rclcpp/issues/2097>`_)
* Contributors: Barry Xu, Chen Lihui, mauropasse
19.0.0 (2023-01-30)
-------------------
* Add default constructor to NodeInterfaces (`#2094 <https://github.com/ros2/rclcpp/issues/2094>`_)
* Fix clock state cached time to be a copy, not a reference. (`#2092 <https://github.com/ros2/rclcpp/issues/2092>`_)
* Fix -Wmaybe-uninitialized warning (`#2081 <https://github.com/ros2/rclcpp/issues/2081>`_)
* Fix the keep_last warning when using system defaults. (`#2082 <https://github.com/ros2/rclcpp/issues/2082>`_)
* Add in a fix for older compilers. (`#2075 <https://github.com/ros2/rclcpp/issues/2075>`_)
* Contributors: Alexander Hans, Chris Lalancette, Shane Loretz
18.0.0 (2022-12-29)
-------------------
* Implement Unified Node Interface (NodeInterfaces class) (`#2041 <https://github.com/ros2/rclcpp/issues/2041>`_)
* Do not throw exception if trying to dequeue an empty intra-process buffer (`#2061 <https://github.com/ros2/rclcpp/issues/2061>`_)
* Move event callback binding to PublisherBase and SubscriptionBase (`#2066 <https://github.com/ros2/rclcpp/issues/2066>`_)
* Implement validity checks for rclcpp::Clock (`#2040 <https://github.com/ros2/rclcpp/issues/2040>`_)
* Explicitly set callback type (`#2059 <https://github.com/ros2/rclcpp/issues/2059>`_)
* Fix logging macros to build with msvc and cpp20 (`#2063 <https://github.com/ros2/rclcpp/issues/2063>`_)
* Add clock type to node_options (`#1982 <https://github.com/ros2/rclcpp/issues/1982>`_)
* Fix nullptr dereference in prune_requests_older_than (`#2008 <https://github.com/ros2/rclcpp/issues/2008>`_)
* Remove templating on to_rcl_subscription_options (`#2056 <https://github.com/ros2/rclcpp/issues/2056>`_)
* Fix SharedFuture from async_send_request never becoming valid (`#2044 <https://github.com/ros2/rclcpp/issues/2044>`_)
* Add in a warning for a KeepLast depth of 0. (`#2048 <https://github.com/ros2/rclcpp/issues/2048>`_)
* Mark rclcpp::Clock::now() as const (`#2050 <https://github.com/ros2/rclcpp/issues/2050>`_)
* Fix a case that did not throw ParameterUninitializedException (`#2036 <https://github.com/ros2/rclcpp/issues/2036>`_)
* Update maintainers (`#2043 <https://github.com/ros2/rclcpp/issues/2043>`_)
* Contributors: Alberto Soragna, Audrow Nash, Chen Lihui, Chris Lalancette, Jeffery Hsu, Lei Liu, Mateusz Szczygielski, Shane Loretz, andrei, mauropasse, methylDragon
17.1.0 (2022-11-02)
-------------------
* MultiThreadExecutor number of threads is at least 2+ in default. (`#2032 <https://github.com/ros2/rclcpp/issues/2032>`_)
* Fix bug that a callback not reached (`#1640 <https://github.com/ros2/rclcpp/issues/1640>`_)
* Set the minimum number of threads of the Multithreaded executor to 2 (`#2030 <https://github.com/ros2/rclcpp/issues/2030>`_)
* check thread whether joinable before join (`#2019 <https://github.com/ros2/rclcpp/issues/2019>`_)
* Set cpplint test timeout to 3 minutes (`#2022 <https://github.com/ros2/rclcpp/issues/2022>`_)
* Make sure to include-what-you-use in the node_interfaces. (`#2018 <https://github.com/ros2/rclcpp/issues/2018>`_)
* Do not clear entities callbacks on destruction (`#2002 <https://github.com/ros2/rclcpp/issues/2002>`_)
* fix mismatched issue if using zero_allocate (`#1995 <https://github.com/ros2/rclcpp/issues/1995>`_)
* Contributors: Alexis Paques, Chen Lihui, Chris Lalancette, Cristóbal Arroyo, Tomoya Fujita, mauropasse, uupks
17.0.0 (2022-09-13)
-------------------
* Make ParameterService and Sync/AsyncParameterClient accept rclcpp::QoS (`#1978 <https://github.com/ros2/rclcpp/issues/1978>`_)
* support regex match for parameter client (`#1992 <https://github.com/ros2/rclcpp/issues/1992>`_)
* operator+= and operator-= for Duration (`#1988 <https://github.com/ros2/rclcpp/issues/1988>`_)
* Revert "Revert "Add a create_timer method to Node and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)" (`#2009 <https://github.com/ros2/rclcpp/issues/2009>`_) (`#2010 <https://github.com/ros2/rclcpp/issues/2010>`_)
* force compiler warning if callback handles not captured (`#2000 <https://github.com/ros2/rclcpp/issues/2000>`_)
* Revert "Add a `create_timer` method to `Node` and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)" (`#2009 <https://github.com/ros2/rclcpp/issues/2009>`_)
* Add a `create_timer` method to `Node` and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)
* [docs] add note about callback lifetime for {on, post}_set_parameter_callback (`#1981 <https://github.com/ros2/rclcpp/issues/1981>`_)
* fix memory leak (`#1994 <https://github.com/ros2/rclcpp/issues/1994>`_)
* Support pre-set and post-set parameter callbacks in addition to on-set-parameter-callback. (`#1947 <https://github.com/ros2/rclcpp/issues/1947>`_)
* Make create_service accept rclcpp::QoS (`#1969 <https://github.com/ros2/rclcpp/issues/1969>`_)
* Make create_client accept rclcpp::QoS (`#1964 <https://github.com/ros2/rclcpp/issues/1964>`_)
* Fix the documentation for rclcpp::ok to be accurate. (`#1965 <https://github.com/ros2/rclcpp/issues/1965>`_)
* use regex for wildcard matching (`#1839 <https://github.com/ros2/rclcpp/issues/1839>`_)
* Revert "Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (`#1821 <https://github.com/ros2/rclcpp/issues/1821>`_) (`#1874 <https://github.com/ros2/rclcpp/issues/1874>`_)" (`#1956 <https://github.com/ros2/rclcpp/issues/1956>`_)
* Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (`#1821 <https://github.com/ros2/rclcpp/issues/1821>`_) (`#1874 <https://github.com/ros2/rclcpp/issues/1874>`_)
* test adjustment for LoanedMessage. (`#1951 <https://github.com/ros2/rclcpp/issues/1951>`_)
* fix virtual dispatch issues identified by clang-tidy (`#1816 <https://github.com/ros2/rclcpp/issues/1816>`_)
* Remove unused on_parameters_set_callback\_ (`#1945 <https://github.com/ros2/rclcpp/issues/1945>`_)
* Fix subscription.is_serialized() for callbacks with message info (`#1950 <https://github.com/ros2/rclcpp/issues/1950>`_)
* wait for subscriptions on another thread. (`#1940 <https://github.com/ros2/rclcpp/issues/1940>`_)
* Fix documentation of `RCLCPP\_[INFO,WARN,...]` (`#1943 <https://github.com/ros2/rclcpp/issues/1943>`_)
* Always trigger guard condition waitset (`#1923 <https://github.com/ros2/rclcpp/issues/1923>`_)
* Add statistics for handle_loaned_message (`#1927 <https://github.com/ros2/rclcpp/issues/1927>`_)
* Drop wrong template specialization (`#1926 <https://github.com/ros2/rclcpp/issues/1926>`_)
* Contributors: Alberto Soragna, Andrew Symington, Barry Xu, Brian, Chen Lihui, Chris Lalancette, Daniel Reuter, Deepanshu Bansal, Hubert Liberacki, Ivan Santiago Paunovic, Jochen Sprickerhof, Nikolai Morin, Shane Loretz, Tomoya Fujita, Tyler Weaver, William Woodall, schrodinbug
16.2.0 (2022-05-03)
-------------------
* Update get_parameter_from_event to follow the function description (`#1922 <https://github.com/ros2/rclcpp/issues/1922>`_)
* Add 'best available' QoS enum values and methods (`#1920 <https://github.com/ros2/rclcpp/issues/1920>`_)
* Contributors: Barry Xu, Jacob Perron
16.1.0 (2022-04-29)
-------------------
* use reinterpret_cast for function pointer conversion. (`#1919 <https://github.com/ros2/rclcpp/issues/1919>`_)
* Contributors: Tomoya Fujita
16.0.1 (2022-04-13)
-------------------
* remove DEFINE_CONTENT_FILTER cmake option (`#1914 <https://github.com/ros2/rclcpp/issues/1914>`_)
* Contributors: Chen Lihui
16.0.0 (2022-04-08)
-------------------
* remove things that were deprecated during galactic (`#1913 <https://github.com/ros2/rclcpp/issues/1913>`_)
* Contributors: William Woodall
15.4.0 (2022-04-05)
-------------------
* add take_data_by_entity_id API to waitable (`#1892 <https://github.com/ros2/rclcpp/issues/1892>`_)
* add content-filtered-topic interfaces (`#1561 <https://github.com/ros2/rclcpp/issues/1561>`_)
* Contributors: Alberto Soragna, Chen Lihui
15.3.0 (2022-03-30)
-------------------
* [NodeParameters] Set name in param info pre-check (`#1908 <https://github.com/ros2/rclcpp/issues/1908>`_)
* Add test-dep ament_cmake_google_benchmark (`#1904 <https://github.com/ros2/rclcpp/issues/1904>`_)
* Add publish by loaned message in GenericPublisher (`#1856 <https://github.com/ros2/rclcpp/issues/1856>`_)
* Contributors: Abrar Rahman Protyasha, Barry Xu, Gaël Écorchard
15.2.0 (2022-03-24)
-------------------
* Add missing ament dependency on rcl_interfaces (`#1903 <https://github.com/ros2/rclcpp/issues/1903>`_)
* Update data callback tests to account for all published samples (`#1900 <https://github.com/ros2/rclcpp/issues/1900>`_)
* Increase timeout for acknowledgments to account for slower Connext settings (`#1901 <https://github.com/ros2/rclcpp/issues/1901>`_)
* clang-tidy: explicit constructors (`#1782 <https://github.com/ros2/rclcpp/issues/1782>`_)
* Add client/service QoS getters (`#1784 <https://github.com/ros2/rclcpp/issues/1784>`_)
* Fix a bunch more rosdoc2 issues in rclcpp. (`#1897 <https://github.com/ros2/rclcpp/issues/1897>`_)
* time_until_trigger returns max time if timer is cancelled (`#1893 <https://github.com/ros2/rclcpp/issues/1893>`_)
* Micro-optimizations in rclcpp (`#1896 <https://github.com/ros2/rclcpp/issues/1896>`_)
* Contributors: Andrea Sorbini, Chris Lalancette, Mauro Passerino, Scott K Logan, William Woodall
15.1.0 (2022-03-01)
-------------------
* spin_all with a zero timeout. (`#1878 <https://github.com/ros2/rclcpp/issues/1878>`_)
* Add RMW listener APIs (`#1579 <https://github.com/ros2/rclcpp/issues/1579>`_)
* Remove fastrtps customization on tests (`#1887 <https://github.com/ros2/rclcpp/issues/1887>`_)
* Install headers to include/${PROJECT_NAME} (`#1888 <https://github.com/ros2/rclcpp/issues/1888>`_)
* Use ament_generate_version_header (`#1886 <https://github.com/ros2/rclcpp/issues/1886>`_)
* use universal reference to support rvalue. (`#1883 <https://github.com/ros2/rclcpp/issues/1883>`_)
* fix one subscription can wait_for_message twice (`#1870 <https://github.com/ros2/rclcpp/issues/1870>`_)
* Add return value version of get_parameter_or (`#1813 <https://github.com/ros2/rclcpp/issues/1813>`_)
* Cleanup time source object lifetimes (`#1867 <https://github.com/ros2/rclcpp/issues/1867>`_)
* add is_spinning() method to executor base class
* Contributors: Alberto Soragna, Chen Lihui, Chris Lalancette, Kenji Miyake, Miguel Company, Shane Loretz, Tomoya Fujita, iRobot ROS
15.0.0 (2022-01-14)
-------------------
* Cleanup the TypeAdapt tests (`#1858 <https://github.com/ros2/rclcpp/issues/1858>`_)
* Cleanup includes (`#1857 <https://github.com/ros2/rclcpp/issues/1857>`_)
* Fix include order and relative paths for cpplint (`#1859 <https://github.com/ros2/rclcpp/issues/1859>`_)
* Rename stringstream in macros to a more unique name (`#1862 <https://github.com/ros2/rclcpp/issues/1862>`_)
* Add non transform capabilities for intra-process (`#1849 <https://github.com/ros2/rclcpp/issues/1849>`_)
* Fix rclcpp documentation build (`#1779 <https://github.com/ros2/rclcpp/issues/1779>`_)
* Contributors: Chris Lalancette, Doug Smith, Gonzo, Jacob Perron, Michel Hidalgo
14.1.0 (2022-01-05)
-------------------
* Use UninitializedStaticallyTypedParameterException (`#1689 <https://github.com/ros2/rclcpp/issues/1689>`_)
* Add wait_for_all_acked support (`#1662 <https://github.com/ros2/rclcpp/issues/1662>`_)
* Add tests for function templates of declare_parameter (`#1747 <https://github.com/ros2/rclcpp/issues/1747>`_)
* Contributors: Barry Xu, Bi0T1N, M. Mostafa Farzan
14.0.0 (2021-12-17)
-------------------
* Fixes for uncrustify 0.72 (`#1844 <https://github.com/ros2/rclcpp/issues/1844>`_)
* use private member to keep the all reference underneath. (`#1845 <https://github.com/ros2/rclcpp/issues/1845>`_)
* Make node base sharable (`#1832 <https://github.com/ros2/rclcpp/issues/1832>`_)
* Add Clock::sleep_for() (`#1828 <https://github.com/ros2/rclcpp/issues/1828>`_)
* Synchronize rcl and std::chrono steady clocks in Clock::sleep_until (`#1830 <https://github.com/ros2/rclcpp/issues/1830>`_)
* Use rclcpp::guard_condition (`#1612 <https://github.com/ros2/rclcpp/issues/1612>`_)
* Call CMake function to generate version header (`#1805 <https://github.com/ros2/rclcpp/issues/1805>`_)
* Use parantheses around logging macro parameter (`#1820 <https://github.com/ros2/rclcpp/issues/1820>`_)
* Remove author by request (`#1818 <https://github.com/ros2/rclcpp/issues/1818>`_)
* Update maintainers (`#1817 <https://github.com/ros2/rclcpp/issues/1817>`_)
* min_forward & min_backward thresholds must not be disabled (`#1815 <https://github.com/ros2/rclcpp/issues/1815>`_)
* Re-add Clock::sleep_until (`#1814 <https://github.com/ros2/rclcpp/issues/1814>`_)
* Fix lifetime of context so it remains alive while its dependent node handles are still in use (`#1754 <https://github.com/ros2/rclcpp/issues/1754>`_)
* Add the interface for pre-shutdown callback (`#1714 <https://github.com/ros2/rclcpp/issues/1714>`_)
* Take message ownership from moved LoanedMessage (`#1808 <https://github.com/ros2/rclcpp/issues/1808>`_)
* Suppress clang dead-store warnings in the benchmarks. (`#1802 <https://github.com/ros2/rclcpp/issues/1802>`_)
* Wait for publisher and subscription to match (`#1777 <https://github.com/ros2/rclcpp/issues/1777>`_)
* Fix unused QoS profile for clock subscription and make ClockQoS the default (`#1801 <https://github.com/ros2/rclcpp/issues/1801>`_)
* Contributors: Abrar Rahman Protyasha, Barry Xu, Chen Lihui, Chris Lalancette, Grey, Jacob Perron, Nikolai Morin, Shane Loretz, Tomoya Fujita, mauropasse
13.1.0 (2021-10-18)
-------------------
* Fix dangerous std::bind capture in TimeSource implementation. (`#1768 <https://github.com/ros2/rclcpp/issues/1768>`_)
* Fix dangerous std::bind capture in ParameterEventHandler implementation. (`#1770 <https://github.com/ros2/rclcpp/issues/1770>`_)
* Handle sigterm, in the same way sigint is being handled. (`#1771 <https://github.com/ros2/rclcpp/issues/1771>`_)
* rclcpp::Node copy constructor: make copy of node_waitables\_ member. (`#1799 <https://github.com/ros2/rclcpp/issues/1799>`_)
* Extend NodeGraph to match what rcl provides. (`#1484 <https://github.com/ros2/rclcpp/issues/1484>`_)
* Context::sleep_for(): replace recursion with do-while to avoid potential stack-overflow. (`#1765 <https://github.com/ros2/rclcpp/issues/1765>`_)
* extend_sub_namespace(): Verify string::empty() before calling string::front(). (`#1764 <https://github.com/ros2/rclcpp/issues/1764>`_)
* Deprecate the `void shared_ptr<MessageT>` subscription callback signatures. (`#1713 <https://github.com/ros2/rclcpp/issues/1713>`_)
* Contributors: Abrar Rahman Protyasha, Chris Lalancette, Emerson Knapp, Geoffrey Biggs, Ivan Santiago Paunovic, Jorge Perez, Tomoya Fujita, William Woodall, Yong-Hao Zou, livanov93
13.0.0 (2021-08-23)
-------------------
* Remove can_be_nullptr assignment check for QNX case. (`#1752 <https://github.com/ros2/rclcpp/issues/1752>`_)

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.12)
cmake_minimum_required(VERSION 3.20)
project(rclcpp)
@@ -10,11 +10,14 @@ find_package(builtin_interfaces REQUIRED)
find_package(libstatistics_collector REQUIRED)
find_package(rcl REQUIRED)
find_package(rcl_interfaces REQUIRED)
find_package(rcl_logging_interface REQUIRED)
find_package(rcl_yaml_param_parser REQUIRED)
find_package(rcpputils REQUIRED)
find_package(rcutils REQUIRED)
find_package(rmw REQUIRED)
find_package(rosgraph_msgs REQUIRED)
find_package(rosidl_dynamic_typesupport REQUIRED)
find_package(rosidl_runtime_c REQUIRED)
find_package(rosidl_runtime_cpp REQUIRED)
find_package(rosidl_typesupport_c REQUIRED)
find_package(rosidl_typesupport_cpp REQUIRED)
@@ -25,6 +28,7 @@ find_package(tracetools REQUIRED)
# Default to C++17
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
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,24 +45,38 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/clock.cpp
src/rclcpp/context.cpp
src/rclcpp/contexts/default_context.cpp
src/rclcpp/create_generic_client.cpp
src/rclcpp/detail/add_guard_condition_to_rcl_wait_set.cpp
src/rclcpp/detail/resolve_intra_process_buffer_type.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
src/rclcpp/detail/utilities.cpp
src/rclcpp/duration.cpp
src/rclcpp/dynamic_typesupport/dynamic_message.cpp
src/rclcpp/dynamic_typesupport/dynamic_message_type.cpp
src/rclcpp/dynamic_typesupport/dynamic_message_type_builder.cpp
src/rclcpp/dynamic_typesupport/dynamic_message_type_support.cpp
src/rclcpp/dynamic_typesupport/dynamic_serialization_support.cpp
src/rclcpp/event.cpp
src/rclcpp/exceptions/exceptions.cpp
src/rclcpp/executable_list.cpp
src/rclcpp/executor.cpp
src/rclcpp/executor_options.cpp
src/rclcpp/executors.cpp
src/rclcpp/executors/executor_entities_collection.cpp
src/rclcpp/executors/executor_entities_collector.cpp
src/rclcpp/executors/executor_notify_waitable.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/experimental/executors/events_executor/events_executor.cpp
src/rclcpp/experimental/timers_manager.cpp
src/rclcpp/future_return_code.cpp
src/rclcpp/generic_client.cpp
src/rclcpp/generic_publisher.cpp
src/rclcpp/generic_service.cpp
src/rclcpp/generic_subscription.cpp
src/rclcpp/graph_listener.cpp
src/rclcpp/guard_condition.cpp
@@ -80,10 +98,12 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/node_interfaces/node_time_source.cpp
src/rclcpp/node_interfaces/node_timers.cpp
src/rclcpp/node_interfaces/node_topics.cpp
src/rclcpp/node_interfaces/node_type_descriptions.cpp
src/rclcpp/node_interfaces/node_waitables.cpp
src/rclcpp/node_options.cpp
src/rclcpp/parameter.cpp
src/rclcpp/parameter_client.cpp
src/rclcpp/parameter_descriptor_wrapper.cpp
src/rclcpp/parameter_event_handler.cpp
src/rclcpp/parameter_events_filter.cpp
src/rclcpp/parameter_map.cpp
@@ -91,8 +111,9 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/parameter_value.cpp
src/rclcpp/publisher_base.cpp
src/rclcpp/qos.cpp
src/rclcpp/qos_event.cpp
src/rclcpp/event_handler.cpp
src/rclcpp/qos_overriding_options.cpp
src/rclcpp/rate.cpp
src/rclcpp/serialization.cpp
src/rclcpp/serialized_message.cpp
src/rclcpp/service.cpp
@@ -109,28 +130,22 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/waitable.cpp
)
find_package(Python3 REQUIRED COMPONENTS Interpreter)
# By default, without the settings below, find_package(Python3) will attempt
# to find the newest python version it can, and additionally will find the
# most specific version. For instance, on a system that has
# /usr/bin/python3.10, /usr/bin/python3.11, and /usr/bin/python3, it will find
# /usr/bin/python3.11, even if /usr/bin/python3 points to /usr/bin/python3.10.
# The behavior we want is to prefer the "system" installed version unless the
# user specifically tells us othewise through the Python3_EXECUTABLE hint.
# Setting CMP0094 to NEW means that the search will stop after the first
# python version is found. Setting Python3_FIND_UNVERSIONED_NAMES means that
# the search will prefer /usr/bin/python3 over /usr/bin/python3.11. And that
# latter functionality is only available in CMake 3.20 or later, so we need
# at least that version.
cmake_policy(SET CMP0094 NEW)
set(Python3_FIND_UNVERSIONED_NAMES FIRST)
# "watch" template for changes
configure_file(
"resource/logging.hpp.em"
"logging.hpp.em.watch"
COPYONLY
)
# generate header with logging macros
set(python_code_logging
"import em"
"em.invoke(['-o', 'include/rclcpp/logging.hpp', '${CMAKE_CURRENT_SOURCE_DIR}/resource/logging.hpp.em'])")
string(REPLACE ";" "$<SEMICOLON>" python_code_logging "${python_code_logging}")
add_custom_command(OUTPUT include/rclcpp/logging.hpp
COMMAND ${CMAKE_COMMAND} -E make_directory "include/rclcpp"
COMMAND Python3::Interpreter ARGS -c "${python_code_logging}"
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/logging.hpp.em.watch"
COMMENT "Expanding logging.hpp.em"
VERBATIM
)
list(APPEND ${PROJECT_NAME}_SRCS
include/rclcpp/logging.hpp)
find_package(Python3 REQUIRED COMPONENTS Interpreter)
file(GLOB interface_files "include/rclcpp/node_interfaces/node_*_interface.hpp")
foreach(interface_file ${interface_files})
@@ -186,22 +201,29 @@ endif()
target_include_directories(${PROJECT_NAME} PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
"$<INSTALL_INTERFACE:include>")
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"
"rcpputils"
"rcutils"
"builtin_interfaces"
"rosgraph_msgs"
"rosidl_typesupport_cpp"
"rosidl_runtime_cpp"
"statistics_msgs"
"tracetools"
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>")
target_link_libraries(${PROJECT_NAME} PUBLIC
${builtin_interfaces_TARGETS}
libstatistics_collector::libstatistics_collector
rcl::rcl
${rcl_interfaces_TARGETS}
rcl_yaml_param_parser::rcl_yaml_param_parser
rcpputils::rcpputils
rcutils::rcutils
rmw::rmw
${rosgraph_msgs_TARGETS}
rosidl_dynamic_typesupport::rosidl_dynamic_typesupport
rosidl_runtime_c::rosidl_runtime_c
rosidl_runtime_cpp::rosidl_runtime_cpp
rosidl_typesupport_cpp::rosidl_typesupport_cpp
${statistics_msgs_TARGETS}
tracetools::tracetools
${CMAKE_THREAD_LIBS_INIT}
)
target_link_libraries(${PROJECT_NAME} PRIVATE
ament_index_cpp::ament_index_cpp
rcl_logging_interface::rcl_logging_interface
)
# Causes the visibility macros to use dllexport rather than dllimport,
@@ -216,24 +238,30 @@ install(
RUNTIME DESTINATION bin
)
# specific order: dependents before dependencies
ament_export_include_directories(include)
# Export old-style CMake variables
ament_export_include_directories("include/${PROJECT_NAME}")
ament_export_libraries(${PROJECT_NAME})
# Export modern CMake targets
ament_export_targets(${PROJECT_NAME})
ament_export_dependencies(ament_index_cpp)
ament_export_dependencies(libstatistics_collector)
ament_export_dependencies(rcl)
ament_export_dependencies(rcpputils)
ament_export_dependencies(rcutils)
ament_export_dependencies(builtin_interfaces)
ament_export_dependencies(rosgraph_msgs)
ament_export_dependencies(rosidl_typesupport_cpp)
ament_export_dependencies(rosidl_typesupport_c)
ament_export_dependencies(rosidl_runtime_cpp)
ament_export_dependencies(rcl_yaml_param_parser)
ament_export_dependencies(statistics_msgs)
ament_export_dependencies(tracetools)
ament_export_dependencies(
builtin_interfaces
libstatistics_collector
rcl
rcl_interfaces
rcl_yaml_param_parser
rcpputils
rcutils
rmw
rosgraph_msgs
rosidl_dynamic_typesupport
rosidl_runtime_c
rosidl_runtime_cpp
rosidl_typesupport_cpp
statistics_msgs
tracetools
)
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
@@ -246,10 +274,16 @@ ament_package()
install(
DIRECTORY include/ ${CMAKE_CURRENT_BINARY_DIR}/include/
DESTINATION include
DESTINATION include/${PROJECT_NAME}
)
if(TEST cppcheck)
# must set the property after ament_package()
set_tests_properties(cppcheck PROPERTIES TIMEOUT 500)
set_tests_properties(cppcheck PROPERTIES TIMEOUT 1200)
endif()
if(TEST cpplint)
set_tests_properties(cpplint PROPERTIES TIMEOUT 180)
endif()
ament_generate_version_header(${PROJECT_NAME})

View File

@@ -21,13 +21,38 @@ GENERATE_LATEX = NO
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
PREDEFINED = RCLCPP_PUBLIC=
EXCLUDE_SYMBOLS += RCLCPP_STATIC_ASSERT_LOGGER
EXCLUDE_SYMBOLS += RCLCPP_LOG
EXCLUDE_SYMBOLS += RCLCPP_LOG_ONCE
EXCLUDE_SYMBOLS += RCLCPP_LOG_EXPRESSION
EXCLUDE_SYMBOLS += RCLCPP_LOG_FUNCTION
EXCLUDE_SYMBOLS += RCLCPP_LOG_SKIPFIRST
EXCLUDE_SYMBOLS += RCLCPP_LOG_TIME_POINT_FUNC
EXCLUDE_SYMBOLS += RCLCPP_LOG_THROTTLE
EXCLUDE_SYMBOLS += RCLCPP_LOG_SKIPFIRST_THROTTLE
EXCLUDE_SYMBOLS += RCLCPP_LOG_STREAM
EXCLUDE_SYMBOLS += RCLCPP_LOG_STREAM_ONCE
EXCLUDE_SYMBOLS += RCLCPP_LOG_STREAM_EXPRESSION
EXCLUDE_SYMBOLS += RCLCPP_LOG_STREAM_FUNCTION
EXCLUDE_SYMBOLS += RCLCPP_LOG_STREAM_SKIPFIRST
EXCLUDE_SYMBOLS += RCLCPP_LOG_STREAM_THROTTLE
EXCLUDE_SYMBOLS += RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE
PREDEFINED += DOXYGEN_ONLY
PREDEFINED += RCLCPP_LOCAL=
PREDEFINED += RCLCPP_PUBLIC=
PREDEFINED += RCLCPP_PUBLIC_TYPE=
PREDEFINED += RCUTILS_WARN_UNUSED=
PREDEFINED += RCPPUTILS_TSA_GUARDED_BY(x)=
PREDEFINED += RCPPUTILS_TSA_PT_GUARDED_BY(x)=
PREDEFINED += RCPPUTILS_TSA_REQUIRES(x)=
DOT_GRAPH_MAX_NODES = 101
# Tag files that do not exist will produce a warning and cross-project linking will not work.
TAGFILES += "../../../../doxygen_tag_files/cppreference-doxygen-web.tag.xml=http://en.cppreference.com/w/"
#TAGFILES += "../../../../doxygen_tag_files/cppreference-doxygen-web.tag.xml=http://en.cppreference.com/w/"
# Consider changing "latest" to the version you want to reference (e.g. beta1 or 1.0.0)
TAGFILES += "../../../../doxygen_tag_files/rcl.tag=http://docs.ros2.org/latest/api/rcl/"
TAGFILES += "../../../../doxygen_tag_files/rmw.tag=http://docs.ros2.org/latest/api/rmw/"
TAGFILES += "../../../../doxygen_tag_files/rcutils.tag=http://docs.ros2.org/latest/api/rcutils/"
#TAGFILES += "../../../../doxygen_tag_files/rcl.tag=http://docs.ros2.org/latest/api/rcl/"
#TAGFILES += "../../../../doxygen_tag_files/rmw.tag=http://docs.ros2.org/latest/api/rmw/"
#TAGFILES += "../../../../doxygen_tag_files/rcutils.tag=http://docs.ros2.org/latest/api/rcutils/"
# Uncomment to generate tag files for cross-project linking.
#GENERATE_TAGFILE = "../../../../doxygen_tag_files/rclcpp.tag"

View File

@@ -1,10 +1,10 @@
This document is a declaration of software quality for the `rclcpp` package, based on the guidelines in [REP-2004](https://www.ros.org/reps/rep-2004.html).
This document is a declaration of software quality for the `rclcpp` package, based on the guidelines in [REP-2004](https://reps.openrobotics.org/rep-2004/).
# rclcpp Quality Declaration
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 Requirements for Quality Level 1 in REP-2004](https://reps.openrobotics.org/rep-2004/).
## Version Policy [1]
@@ -55,7 +55,7 @@ All pull requests will be peer-reviewed, check [ROS 2 Developer Guide](https://d
### Continuous Integration [2.iv]
All pull requests must pass CI on all [tier 1 platforms](https://www.ros.org/reps/rep-2000.html#support-tiers)
All pull requests must pass CI on all [tier 1 platforms](https://reps.openrobotics.org/rep-2000/#support-tiers)
Currently nightly results can be seen here:
@@ -94,7 +94,7 @@ There is an automated test which runs a linter that ensures each file has at lea
### Feature Testing [4.i]
Each feature in `rclcpp` has corresponding tests which simulate typical usage, and they are located in the [`test`](https://github.com/ros2/rclcpp/tree/master/test) directory.
Each feature in `rclcpp` has corresponding tests which simulate typical usage, and they are located in the [`test`](https://github.com/ros2/rclcpp/tree/rolling/test) directory.
New features are required to have tests before being added.
Currently nightly test results can be seen here:
@@ -129,7 +129,7 @@ Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly
`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.
The performance tests of `rclcpp` are located in the [test/benchmark directory](https://github.com/ros2/rclcpp/tree/master/rclcpp/test/benchmark).
The performance tests of `rclcpp` are located in the [test/benchmark directory](https://github.com/ros2/rclcpp/tree/rolling/rclcpp/test/benchmark).
System level performance benchmarks that cover features of `rclcpp` can be found at:
* [Benchmarks](http://build.ros2.org/view/Rci/job/Rci__benchmark_ubuntu_focal_amd64/BenchmarkTable/)
@@ -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 ROS 2 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.
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/)
@@ -163,49 +163,49 @@ It also has several test dependencies, which do not affect the resulting quality
The `libstatistics_collector` package provides lightweight aggregation utilities to collect statistics and measure message metrics.
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros-tooling/libstatistics_collector/tree/master/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros-tooling/libstatistics_collector/tree/rolling/QUALITY_DECLARATION.md).
#### `rcl`
`rcl` a library to support implementation of language specific ROS 2 Client Libraries.
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcl/blob/master/rcl/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcl/blob/rolling/rcl/QUALITY_DECLARATION.md).
#### `rcl_yaml_param_parser`
The `rcl_yaml_param_parser` package provides an API that is used to parse YAML configuration files which may be used to configure ROS and specific nodes.
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcl/tree/master/rcl_yaml_param_parser/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcl/tree/rolling/rcl_yaml_param_parser/QUALITY_DECLARATION.md).
#### `rcpputils`
The `rcpputils` package provides an API which contains common utilities and data structures useful when programming in C++.
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcpputils/blob/master/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcpputils/blob/rolling/QUALITY_DECLARATION.md).
#### `rcutils`
The `rcutils` package provides an API which contains common utilities and data structures useful when programming in C.
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcutils/blob/master/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcutils/blob/rolling/QUALITY_DECLARATION.md).
#### `rmw`
`rmw` is the ROS 2 middleware library.
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rmw/blob/master/rmw/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rmw/blob/rolling/rmw/QUALITY_DECLARATION.md).
#### `statistics_msgs`
The `statistics_msgs` package contains ROS 2 message definitions for reporting statistics for topics and system resources.
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/master/statistics_msgs/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/rolling/statistics_msgs/QUALITY_DECLARATION.md).
#### `tracetools`
The `tracetools` package provides utilities for instrumenting the code in `rclcpp` so that it may be traced for debugging and performance analysis.
It is **Quality Level 1**, see its [Quality Declaration document](https://gitlab.com/ros-tracing/ros2_tracing/-/blob/master/tracetools/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/ros2_tracing/blob/rolling/tracetools/QUALITY_DECLARATION.md).
### Direct Runtime non-ROS Dependency [5.iii]
@@ -213,7 +213,7 @@ It is **Quality Level 1**, see its [Quality Declaration document](https://gitlab
## Platform Support [6]
`rclcpp` supports all of the tier 1 platforms as described in [REP-2000](https://www.ros.org/reps/rep-2000.html#support-tiers), and tests each change against all of them.
`rclcpp` supports all of the tier 1 platforms as described in [REP-2000](https://reps.openrobotics.org/rep-2000/#support-tiers), and tests each change against all of them.
Currently nightly build status can be seen here:
* [linux-aarch64_release](https://ci.ros2.org/view/nightly/job/nightly_linux-aarch64_release/lastBuild/rclcpp/)
@@ -225,4 +225,4 @@ Currently nightly build status can be seen here:
### Vulnerability Disclosure Policy [7.i]
This package conforms to the Vulnerability Disclosure Policy in [REP-2006](https://www.ros.org/reps/rep-2006.html).
This package conforms to the Vulnerability Disclosure Policy in [REP-2006](https://reps.openrobotics.org/rep-2006/).

View File

@@ -2,7 +2,7 @@
The ROS client library in C++.
Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) for a complete list of its main components and features.
The link to the latest rclcpp API documentation, which includes a complete list of its main components and features, can be found on the [rclcpp package info page](https://docs.ros.org/en/rolling/p/rclcpp).
## Quality Declaration

View File

@@ -434,4 +434,3 @@
- (tfoote) There should be no jumps in steady time. If there's a big change in system time, it doesn't necessarily mean that time jumped, just that you might have been sleeping for a long time. Most ntp systems adjust the slew rate these days instead of jumping but still that's an external process and I don't know of any APIs to introspect the state of the clock. I'm not sure that we have a way to detect jumps in time for system or steady time. To that end I think that we should be clear that we only provide callbacks when simulation time starts or stops, or simulation time jumps. We should also strongly recommend that operators not actively adjust their system clocks while running ROS nodes.
- (jacobperron) I agree with Tully, if we don't have a way to detect system time jumps then I think we should just document that this only works with ROS time. In addition to documentation, we could log an info or warning message if the user registers jump callback with steady or system time, but it may be unnecessarily noisy.

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

View File

@@ -0,0 +1,29 @@
# Proposed node parameters callback Design
## Introduction:
The original requirement came in **gazebo_ros_pkgs** for setting individual wheel slip parameters based on global wheel slip value [link to original issue](https://github.com/ros-simulation/gazebo_ros_pkgs/pull/1365).
The main requirement is to set one or more parameters after another parameter is set successfully.
Additionally, it would be nice if users could be notified locally (via a callback) when parameters have been set successfully (i.e. post validation).
Related discussion can be found in [#609](https://github.com/ros2/rclcpp/issues/609) [#1789](https://github.com/ros2/rclcpp/pull/1789)
With the current parameters API, the `add_on_set_parameters_callback` is intended for validation of parameter values before they are set, it should **not** cause any side-effects.
There is also the `ParameterEventHandler` that publishes changes to node parameters on `/parameter_events` topic for external nodes to see. Though the node could subscribe to the `/parameter_events` topic to be notified of changes to its own parameters, it is less than ideal since there is a delay caused by waiting for an executor to process the callback.
We propose adding a `PostSetParametersCallbackHandle` for successful parameter set similar to `OnSetParametersCallbackHandle` for parameter validation. Also, we propose adding a `PreSetParametersCallbackHandle` useful for modifying list of parameters being set.
The validation callback is often abused to trigger side effects in the code, for instance updating class attributes even before a parameter has been set successfully. Instead of relying on the `/parameter_events` topic to be notified of parameter changes, users can register a callback with a new API, `add_post_set_parameters_callback`.
It is possible to use the proposed `add_post_set_parameters_callback` for setting additional parameters, but this might result in infinite recursion and does not allow those additional parameters to be set atomically with the original parameter(s) changed.
To workaround these issues, we propose adding a "pre set" callback type that can be registered with `add_pre_set_parameters_callback`, which will be triggered before the validation callbacks and can be used to modify the parameter list.
![Desgin API](https://github.com/ros2/rclcpp/blob/deepanshu/local-param-changed-callback-support/rclcpp/doc/param_callback_design.png?raw=true)
## Alternatives
* Users could call `set_parameter` while processing a message from the `/parameter_events` topic, however, there is extra overhead in having to create subscription (as noted earlier).
* Users could call `set_parameter` inside the "on set" parameters callback, however it is not well-defined how side-effects should handle cases where parameter validation fails.

View File

@@ -15,6 +15,7 @@
#ifndef RCLCPP__ALLOCATOR__ALLOCATOR_COMMON_HPP_
#define RCLCPP__ALLOCATOR__ALLOCATOR_COMMON_HPP_
#include <cstring>
#include <memory>
#include "rcl/allocator.h"
@@ -26,10 +27,39 @@ namespace rclcpp
namespace allocator
{
template<typename T>
using clean_t = std::remove_cv_t<std::remove_reference_t<T>>;
// Primary template: false
template<typename, typename = std::void_t<>>
struct has_get_rcl_allocator : std::false_type {};
// Specialization: true if expression is valid
template<typename T>
struct has_get_rcl_allocator<T,
std::void_t<
decltype(std::declval<clean_t<T> &>().get_rcl_allocator())
>
>
: std::bool_constant<
std::is_same_v<
decltype(std::declval<clean_t<T> &>().get_rcl_allocator()),
rcl_allocator_t
>
>
{};
// Helper variable template
template<typename T>
inline constexpr bool has_get_rcl_allocator_v =
has_get_rcl_allocator<T>::value;
template<typename T, typename Alloc>
using AllocRebind = typename std::allocator_traits<Alloc>::template rebind_traits<T>;
template<typename Alloc>
[[deprecated("Conversion of C++ allocators to C style is not valid, as the size on deallocate"
"can not be determined. This will be remove in future versions of ros.")]]
void * retyped_allocate(size_t size, void * untyped_allocator)
{
auto typed_allocator = static_cast<Alloc *>(untyped_allocator);
@@ -39,7 +69,27 @@ void * retyped_allocate(size_t size, void * untyped_allocator)
return std::allocator_traits<Alloc>::allocate(*typed_allocator, size);
}
template<typename Alloc>
[[deprecated("Conversion of C++ allocators to C style is not valid, as the size on deallocate"
"can not be determined. This will be remove in future versions of ros.")]]
void * retyped_zero_allocate(size_t number_of_elem, size_t size_of_elem, void * untyped_allocator)
{
auto typed_allocator = static_cast<Alloc *>(untyped_allocator);
if (!typed_allocator) {
throw std::runtime_error("Received incorrect allocator type");
}
size_t size = number_of_elem * size_of_elem;
void * allocated_memory =
std::allocator_traits<Alloc>::allocate(*typed_allocator, size);
if (allocated_memory) {
std::memset(allocated_memory, 0, size);
}
return allocated_memory;
}
template<typename T, typename Alloc>
[[deprecated("Conversion of C++ allocators to C style is not valid, as the size on deallocate"
"can not be determined. This will be remove in future versions of ros.")]]
void retyped_deallocate(void * untyped_pointer, void * untyped_allocator)
{
auto typed_allocator = static_cast<Alloc *>(untyped_allocator);
@@ -51,6 +101,8 @@ void retyped_deallocate(void * untyped_pointer, void * untyped_allocator)
}
template<typename T, typename Alloc>
[[deprecated("Conversion of C++ allocators to C style is not valid, as the size on deallocate"
"can not be determined. This will be remove in future versions of ros.")]]
void * retyped_reallocate(void * untyped_pointer, size_t size, void * untyped_allocator)
{
auto typed_allocator = static_cast<Alloc *>(untyped_allocator);
@@ -68,11 +120,15 @@ template<
typename T,
typename Alloc,
typename std::enable_if<!std::is_same<Alloc, std::allocator<void>>::value>::type * = nullptr>
[[deprecated("Conversion of C++ allocators to C style is not valid, as the size on deallocate"
"can not be determined. This will be remove in future versions of ros. To suppress this warning"
"define the method 'rcl_allocator_t get_rcl_allocator()' on your allocator")]]
rcl_allocator_t get_rcl_allocator(Alloc & allocator)
{
rcl_allocator_t rcl_allocator = rcl_get_default_allocator();
#ifndef _WIN32
rcl_allocator.allocate = &retyped_allocate<Alloc>;
rcl_allocator.zero_allocate = &retyped_zero_allocate<Alloc>;
rcl_allocator.deallocate = &retyped_deallocate<T, Alloc>;
rcl_allocator.reallocate = &retyped_reallocate<T, Alloc>;
rcl_allocator.state = &allocator;

View File

@@ -41,7 +41,7 @@ public:
}
template<typename T>
AllocatorDeleter(const AllocatorDeleter<T> & a)
explicit AllocatorDeleter(const AllocatorDeleter<T> & a)
{
allocator_ = a.get_allocator();
}
@@ -69,18 +69,17 @@ private:
};
template<typename Alloc, typename T, typename D>
void set_allocator_for_deleter(D * deleter, Alloc * alloc)
void set_allocator_for_deleter([[maybe_unused]] D * deleter, [[maybe_unused]] Alloc * alloc)
{
(void) alloc;
(void) deleter;
throw std::runtime_error("Reached unexpected template specialization");
}
template<typename T, typename U>
void set_allocator_for_deleter(std::default_delete<T> * deleter, std::allocator<U> * alloc)
void set_allocator_for_deleter(
[[maybe_unused]] std::default_delete<T> * deleter,
[[maybe_unused]] std::allocator<U> * alloc)
{
(void) deleter;
(void) alloc;
// This function is intentionally left empty.
}
template<typename Alloc, typename T>

View File

@@ -45,9 +45,9 @@ struct AnyExecutable
rclcpp::ClientBase::SharedPtr client;
rclcpp::Waitable::SharedPtr waitable;
// These are used to keep the scope on the containing items
rclcpp::CallbackGroup::SharedPtr callback_group;
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base;
std::shared_ptr<void> data;
rclcpp::CallbackGroup::SharedPtr callback_group {nullptr};
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base {nullptr};
std::shared_ptr<void> data {nullptr};
};
} // namespace rclcpp

View File

@@ -156,7 +156,7 @@ public:
const std::shared_ptr<rmw_request_id_t> & request_header,
std::shared_ptr<typename ServiceT::Request> request)
{
TRACEPOINT(callback_start, static_cast<const void *>(this), false);
TRACETOOLS_TRACEPOINT(callback_start, static_cast<const void *>(this), false);
if (std::holds_alternative<std::monostate>(callback_)) {
// TODO(ivanpauno): Remove the set method, and force the users of this class
// to pass a callback at construnciton.
@@ -165,11 +165,13 @@ public:
if (std::holds_alternative<SharedPtrDeferResponseCallback>(callback_)) {
const auto & cb = std::get<SharedPtrDeferResponseCallback>(callback_);
cb(request_header, std::move(request));
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
return nullptr;
}
if (std::holds_alternative<SharedPtrDeferResponseCallbackWithServiceHandle>(callback_)) {
const auto & cb = std::get<SharedPtrDeferResponseCallbackWithServiceHandle>(callback_);
cb(service_handle, request_header, std::move(request));
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
return nullptr;
}
// auto response = allocate_shared<typename ServiceT::Response, Allocator>();
@@ -182,7 +184,7 @@ public:
const auto & cb = std::get<SharedPtrWithRequestHeaderCallback>(callback_);
cb(request_header, std::move(request), response);
}
TRACEPOINT(callback_end, static_cast<const void *>(this));
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
return response;
}
@@ -191,10 +193,14 @@ public:
#ifndef TRACETOOLS_DISABLED
std::visit(
[this](auto && arg) {
TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
tracetools::get_symbol(arg));
if (TRACETOOLS_TRACEPOINT_ENABLED(rclcpp_callback_register)) {
char * symbol = tracetools::get_symbol(arg);
TRACETOOLS_DO_TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
symbol);
std::free(symbol);
}
}, callback_);
#endif // TRACETOOLS_DISABLED
}

View File

@@ -15,12 +15,14 @@
#ifndef RCLCPP__ANY_SUBSCRIPTION_CALLBACK_HPP_
#define RCLCPP__ANY_SUBSCRIPTION_CALLBACK_HPP_
#include <atomic>
#include <functional>
#include <memory>
#include <mutex>
#include <stdexcept>
#include <type_traits>
#include <utility>
#include <variant> // NOLINT[build/include_order]
#include <variant>
#include "rosidl_runtime_cpp/traits.hpp"
#include "tracetools/tracetools.h"
@@ -30,19 +32,19 @@
#include "rclcpp/detail/subscription_callback_type_helper.hpp"
#include "rclcpp/function_traits.hpp"
#include "rclcpp/message_info.hpp"
#include "rclcpp/serialization.hpp"
#include "rclcpp/serialized_message.hpp"
#include "rclcpp/type_adapter.hpp"
template<class>
inline constexpr bool always_false_v = false;
namespace rclcpp
{
namespace detail
{
template<class>
inline constexpr bool always_false_v = false;
template<typename MessageT, typename AllocatorT>
struct MessageDeleterHelper
{
@@ -158,13 +160,14 @@ struct AnySubscriptionCallbackPossibleTypes
template<
typename MessageT,
typename AllocatorT,
bool is_adapted_type = rclcpp::TypeAdapter<MessageT>::is_specialized::value
bool is_adapted_type = rclcpp::TypeAdapter<MessageT>::is_specialized::value,
bool is_serialized_type = serialization_traits::is_serialized_message_class<MessageT>::value
>
struct AnySubscriptionCallbackHelper;
/// Specialization for when MessageT is not a TypeAdapter.
template<typename MessageT, typename AllocatorT>
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, false>
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, false, false>
{
using CallbackTypes = AnySubscriptionCallbackPossibleTypes<MessageT, AllocatorT>;
@@ -194,7 +197,7 @@ struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, false>
/// Specialization for when MessageT is a TypeAdapter.
template<typename MessageT, typename AllocatorT>
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, true>
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, true, false>
{
using CallbackTypes = AnySubscriptionCallbackPossibleTypes<MessageT, AllocatorT>;
@@ -232,6 +235,26 @@ struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, true>
>;
};
/// Specialization for when MessageT is a SerializedMessage to exclude duplicated declarations.
template<typename MessageT, typename AllocatorT>
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, false, true>
{
using CallbackTypes = AnySubscriptionCallbackPossibleTypes<MessageT, AllocatorT>;
using variant_type = std::variant<
typename CallbackTypes::ConstRefSerializedMessageCallback,
typename CallbackTypes::ConstRefSerializedMessageWithInfoCallback,
typename CallbackTypes::UniquePtrSerializedMessageCallback,
typename CallbackTypes::UniquePtrSerializedMessageWithInfoCallback,
typename CallbackTypes::SharedConstPtrSerializedMessageCallback,
typename CallbackTypes::SharedConstPtrSerializedMessageWithInfoCallback,
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageCallback,
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageWithInfoCallback,
typename CallbackTypes::SharedPtrSerializedMessageCallback,
typename CallbackTypes::SharedPtrSerializedMessageWithInfoCallback
>;
};
} // namespace detail
template<
@@ -354,13 +377,19 @@ public:
allocator::set_allocator_for_deleter(&ros_message_type_deleter_, &ros_message_type_allocator_);
}
[[deprecated("use AnySubscriptionCallback(const AllocatorT & allocator) instead")]]
explicit
AnySubscriptionCallback(std::shared_ptr<AllocatorT> allocator) // NOLINT[runtime/explicit]
: AnySubscriptionCallback(*NotNull<AllocatorT>(allocator.get(), "invalid allocator").pointer)
{}
AnySubscriptionCallback(const AnySubscriptionCallback &) = default;
AnySubscriptionCallback(const AnySubscriptionCallback & other)
: callback_variant_(other.callback_variant_),
callback_disabled_(other.callback_disabled_.load()),
subscribed_type_allocator_(other.subscribed_type_allocator_),
subscribed_type_deleter_(other.subscribed_type_deleter_),
ros_message_type_allocator_(other.ros_message_type_allocator_),
ros_message_type_deleter_(other.ros_message_type_deleter_),
serialized_message_allocator_(other.serialized_message_allocator_),
serialized_message_deleter_(other.serialized_message_deleter_)
{
allocator::set_allocator_for_deleter(&subscribed_type_deleter_, &subscribed_type_allocator_);
allocator::set_allocator_for_deleter(&ros_message_type_deleter_, &ros_message_type_allocator_);
}
/// Generic function for setting the callback.
/**
@@ -382,12 +411,27 @@ public:
constexpr auto is_deprecated =
rclcpp::function_traits::same_arguments<
typename scbth::callback_type,
std::function<void(std::shared_ptr<MessageT>)>
>::value
||
std::function<void(std::shared_ptr<SubscribedType>)>
>::value ||
rclcpp::function_traits::same_arguments<
typename scbth::callback_type,
std::function<void(std::shared_ptr<MessageT>, const rclcpp::MessageInfo &)>
std::function<void(std::shared_ptr<SubscribedType>, const rclcpp::MessageInfo &)>
>::value ||
rclcpp::function_traits::same_arguments<
typename scbth::callback_type,
std::function<void(std::shared_ptr<ROSMessageType>)>
>::value ||
rclcpp::function_traits::same_arguments<
typename scbth::callback_type,
std::function<void(std::shared_ptr<ROSMessageType>, const rclcpp::MessageInfo &)>
>::value ||
rclcpp::function_traits::same_arguments<
typename scbth::callback_type,
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)>
>::value ||
rclcpp::function_traits::same_arguments<
typename scbth::callback_type,
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>, const rclcpp::MessageInfo &)>
>::value;
// Use the discovered type to force the type of callback when assigning
@@ -406,10 +450,12 @@ public:
/// Function for shared_ptr to non-const MessageT, which is deprecated.
template<typename SetT>
// TODO(wjwwood): enable this deprecation after Galactic
// [[deprecated(
// "use 'void (std::shared_ptr<const MessageT>)' instead"
// )]]
// *INDENT-OFF*
#if !defined(RCLCPP_AVOID_DEPRECATIONS_FOR_UNIT_TESTS)
// suppress deprecation warnings in `test_any_subscription_callback.cpp`
[[deprecated("use 'void(std::shared_ptr<const MessageT>)' instead")]]
#endif
// *INDENT-ON*
void
set_deprecated(std::function<void(std::shared_ptr<SetT>)> callback)
{
@@ -418,16 +464,34 @@ public:
/// Function for shared_ptr to non-const MessageT with MessageInfo, which is deprecated.
template<typename SetT>
// TODO(wjwwood): enable this deprecation after Galactic
// [[deprecated(
// "use 'void (std::shared_ptr<const MessageT>, const rclcpp::MessageInfo &)' instead"
// )]]
// *INDENT-OFF*
#if !defined(RCLCPP_AVOID_DEPRECATIONS_FOR_UNIT_TESTS)
// suppress deprecation warnings in `test_any_subscription_callback.cpp`
[[deprecated(
"use 'void(std::shared_ptr<const MessageT>, const rclcpp::MessageInfo &)' instead"
)]]
#endif
// *INDENT-ON*
void
set_deprecated(std::function<void(std::shared_ptr<SetT>, const rclcpp::MessageInfo &)> callback)
{
callback_variant_ = callback;
}
/// Disable the callback from being called during dispatch.
void disable()
{
std::unique_lock<std::recursive_mutex> callback_lock(callback_mutex_);
callback_disabled_.store(true);
}
/// Enable the callback to be called during dispatch.
void enable()
{
std::unique_lock<std::recursive_mutex> callback_lock(callback_mutex_);
callback_disabled_.store(false);
}
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
create_ros_unique_ptr_from_ros_shared_ptr_message(
const std::shared_ptr<const ROSMessageType> & message)
@@ -474,13 +538,35 @@ public:
}
}
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
convert_custom_type_to_ros_message_unique_ptr(const SubscribedType & msg)
{
if constexpr (rclcpp::TypeAdapter<MessageT>::is_specialized::value) {
auto ptr = ROSMessageTypeAllocatorTraits::allocate(ros_message_type_allocator_, 1);
ROSMessageTypeAllocatorTraits::construct(ros_message_type_allocator_, ptr);
rclcpp::TypeAdapter<MessageT>::convert_to_ros_message(msg, *ptr);
return std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, ros_message_type_deleter_);
} else {
static_assert(
!sizeof(MessageT *),
"convert_custom_type_to_ros_message_unique_ptr() "
"unexpectedly called without specialized TypeAdapter");
}
}
// Dispatch when input is a ros message and the output could be anything.
void
template<typename TMsg = ROSMessageType>
typename std::enable_if<!serialization_traits::is_serialized_message_class<TMsg>::value,
void>::type
dispatch(
std::shared_ptr<ROSMessageType> message,
const rclcpp::MessageInfo & message_info)
{
TRACEPOINT(callback_start, static_cast<const void *>(this), false);
std::unique_lock<std::recursive_mutex> callback_lock(callback_mutex_);
if (callback_disabled_.load()) {
return;
}
TRACETOOLS_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) {
@@ -568,19 +654,23 @@ public:
}
// condition to catch unhandled callback types
else { // NOLINT[readability/braces]
static_assert(always_false_v<T>, "unhandled callback type");
static_assert(detail::always_false_v<T>, "unhandled callback type");
}
}, callback_variant_);
TRACEPOINT(callback_end, static_cast<const void *>(this));
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
}
// Dispatch when input is a serialized message and the output could be anything.
void
dispatch(
std::shared_ptr<rclcpp::SerializedMessage> serialized_message,
std::shared_ptr<const rclcpp::SerializedMessage> serialized_message,
const rclcpp::MessageInfo & message_info)
{
TRACEPOINT(callback_start, static_cast<const void *>(this), false);
std::unique_lock<std::recursive_mutex> callback_lock(callback_mutex_);
if (callback_disabled_.load()) {
return;
}
TRACETOOLS_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) {
@@ -648,18 +738,22 @@ public:
}
// condition to catch unhandled callback types
else { // NOLINT[readability/braces]
static_assert(always_false_v<T>, "unhandled callback type");
static_assert(detail::always_false_v<T>, "unhandled callback type");
}
}, callback_variant_);
TRACEPOINT(callback_end, static_cast<const void *>(this));
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
}
void
dispatch_intra_process(
std::shared_ptr<const ROSMessageType> message,
std::shared_ptr<const SubscribedType> message,
const rclcpp::MessageInfo & message_info)
{
TRACEPOINT(callback_start, static_cast<const void *>(this), true);
std::unique_lock<std::recursive_mutex> callback_lock(callback_mutex_);
if (callback_disabled_.load()) {
return;
}
TRACETOOLS_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) {
@@ -675,65 +769,89 @@ public:
// conditions for custom type
if constexpr (is_ta && std::is_same_v<T, ConstRefCallback>) {
auto local_message = convert_ros_message_to_custom_type_unique_ptr(*message);
callback(*local_message);
callback(*message);
} else if constexpr (is_ta && std::is_same_v<T, ConstRefWithInfoCallback>) { // NOLINT
auto local_message = convert_ros_message_to_custom_type_unique_ptr(*message);
callback(*local_message, message_info);
callback(*message, message_info);
} else if constexpr ( // NOLINT[readability/braces]
is_ta && (
std::is_same_v<T, UniquePtrCallback>||
std::is_same_v<T, SharedPtrCallback>
))
{
callback(convert_ros_message_to_custom_type_unique_ptr(*message));
callback(create_custom_unique_ptr_from_custom_shared_ptr_message(message));
} else if constexpr ( // NOLINT[readability/braces]
is_ta && (
std::is_same_v<T, UniquePtrWithInfoCallback>||
std::is_same_v<T, SharedPtrWithInfoCallback>
))
{
callback(convert_ros_message_to_custom_type_unique_ptr(*message), message_info);
callback(create_custom_unique_ptr_from_custom_shared_ptr_message(message), message_info);
} else if constexpr ( // NOLINT[readability/braces]
is_ta && (
std::is_same_v<T, SharedConstPtrCallback>||
std::is_same_v<T, ConstRefSharedConstPtrCallback>
))
{
callback(convert_ros_message_to_custom_type_unique_ptr(*message));
callback(message);
} else if constexpr ( // NOLINT[readability/braces]
is_ta && (
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>
))
{
callback(convert_ros_message_to_custom_type_unique_ptr(*message), message_info);
callback(message, message_info);
}
// conditions for ros message type
else if constexpr (std::is_same_v<T, ConstRefROSMessageCallback>) { // NOLINT
callback(*message);
} else if constexpr (std::is_same_v<T, ConstRefWithInfoROSMessageCallback>) {
callback(*message, message_info);
else if constexpr (std::is_same_v<T, ConstRefROSMessageCallback>) { // NOLINT[readability/braces]
if constexpr (is_ta) {
auto local = convert_custom_type_to_ros_message_unique_ptr(*message);
callback(*local);
} else {
callback(*message);
}
} else if constexpr (std::is_same_v<T, ConstRefWithInfoROSMessageCallback>) { // NOLINT[readability/braces]
if constexpr (is_ta) {
auto local = convert_custom_type_to_ros_message_unique_ptr(*message);
callback(*local, message_info);
} else {
callback(*message, message_info);
}
} else if constexpr ( // NOLINT[readability/braces]
std::is_same_v<T, UniquePtrROSMessageCallback>||
std::is_same_v<T, SharedPtrROSMessageCallback>)
{
callback(create_ros_unique_ptr_from_ros_shared_ptr_message(message));
if constexpr (is_ta) {
callback(convert_custom_type_to_ros_message_unique_ptr(*message));
} else {
callback(create_ros_unique_ptr_from_ros_shared_ptr_message(message));
}
} else if constexpr ( // NOLINT[readability/braces]
std::is_same_v<T, UniquePtrWithInfoROSMessageCallback>||
std::is_same_v<T, SharedPtrWithInfoROSMessageCallback>)
{
callback(create_ros_unique_ptr_from_ros_shared_ptr_message(message), message_info);
if constexpr (is_ta) {
callback(convert_custom_type_to_ros_message_unique_ptr(*message), message_info);
} else {
callback(create_ros_unique_ptr_from_ros_shared_ptr_message(message), message_info);
}
} else if constexpr ( // NOLINT[readability/braces]
std::is_same_v<T, SharedConstPtrROSMessageCallback>||
std::is_same_v<T, ConstRefSharedConstPtrROSMessageCallback>)
{
callback(message);
if constexpr (is_ta) {
callback(convert_custom_type_to_ros_message_unique_ptr(*message));
} else {
callback(message);
}
} else if constexpr ( // NOLINT[readability/braces]
std::is_same_v<T, SharedConstPtrWithInfoROSMessageCallback>||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoROSMessageCallback>)
{
callback(message, message_info);
if constexpr (is_ta) {
callback(convert_custom_type_to_ros_message_unique_ptr(*message), message_info);
} else {
callback(message, message_info);
}
}
// condition to catch SerializedMessage types
else if constexpr ( // NOLINT[readability/braces]
@@ -754,18 +872,22 @@ public:
}
// condition to catch unhandled callback types
else { // NOLINT[readability/braces]
static_assert(always_false_v<T>, "unhandled callback type");
static_assert(detail::always_false_v<T>, "unhandled callback type");
}
}, callback_variant_);
TRACEPOINT(callback_end, static_cast<const void *>(this));
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
}
void
dispatch_intra_process(
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> message,
std::unique_ptr<SubscribedType, SubscribedTypeDeleter> message,
const rclcpp::MessageInfo & message_info)
{
TRACEPOINT(callback_start, static_cast<const void *>(this), true);
std::unique_lock<std::recursive_mutex> callback_lock(callback_mutex_);
if (callback_disabled_.load()) {
return;
}
TRACETOOLS_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) {
@@ -776,70 +898,98 @@ public:
// Dispatch.
std::visit(
[&message, &message_info, this](auto && callback) {
// clang complains that 'this' lambda capture is unused, which is true
// in *some* specializations of this template, but not others. Just
// quiet it down.
(void)this;
using T = std::decay_t<decltype(callback)>;
static constexpr bool is_ta = rclcpp::TypeAdapter<MessageT>::is_specialized::value;
// conditions for custom type
if constexpr (is_ta && std::is_same_v<T, ConstRefCallback>) {
auto local_message = convert_ros_message_to_custom_type_unique_ptr(*message);
callback(*local_message);
callback(*message);
} else if constexpr (is_ta && std::is_same_v<T, ConstRefWithInfoCallback>) { // NOLINT
auto local_message = convert_ros_message_to_custom_type_unique_ptr(*message);
callback(*local_message, message_info);
callback(*message, message_info);
} else if constexpr ( // NOLINT[readability/braces]
is_ta && (
std::is_same_v<T, UniquePtrCallback>||
std::is_same_v<T, SharedPtrCallback>
))
std::is_same_v<T, SharedPtrCallback>))
{
callback(convert_ros_message_to_custom_type_unique_ptr(*message));
callback(std::move(message));
} else if constexpr ( // NOLINT[readability/braces]
is_ta && (
std::is_same_v<T, UniquePtrWithInfoCallback>||
std::is_same_v<T, SharedPtrWithInfoCallback>
))
{
callback(convert_ros_message_to_custom_type_unique_ptr(*message), message_info);
callback(std::move(message), message_info);
} else if constexpr ( // NOLINT[readability/braces]
is_ta && (
std::is_same_v<T, SharedConstPtrCallback>||
std::is_same_v<T, ConstRefSharedConstPtrCallback>
))
{
callback(convert_ros_message_to_custom_type_unique_ptr(*message));
callback(std::move(message));
} else if constexpr ( // NOLINT[readability/braces]
is_ta && (
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>
))
{
callback(convert_ros_message_to_custom_type_unique_ptr(*message), message_info);
callback(std::move(message), message_info);
}
// conditions for ros message type
else if constexpr (std::is_same_v<T, ConstRefROSMessageCallback>) { // NOLINT
callback(*message);
} else if constexpr (std::is_same_v<T, ConstRefWithInfoROSMessageCallback>) {
callback(*message, message_info);
else if constexpr (std::is_same_v<T, ConstRefROSMessageCallback>) { // NOLINT[readability/braces]
if constexpr (is_ta) {
auto local = convert_custom_type_to_ros_message_unique_ptr(*message);
callback(*local);
} else {
callback(*message);
}
} else if constexpr (std::is_same_v<T, ConstRefWithInfoROSMessageCallback>) { // NOLINT[readability/braces]
if constexpr (is_ta) {
auto local = convert_custom_type_to_ros_message_unique_ptr(*message);
callback(*local, message_info);
} else {
callback(*message, message_info);
}
} else if constexpr ( // NOLINT[readability/braces]
std::is_same_v<T, UniquePtrROSMessageCallback>||
std::is_same_v<T, SharedPtrROSMessageCallback>)
{
callback(std::move(message));
if constexpr (is_ta) {
callback(convert_custom_type_to_ros_message_unique_ptr(*message));
} else {
callback(std::move(message));
}
} else if constexpr ( // NOLINT[readability/braces]
std::is_same_v<T, UniquePtrWithInfoROSMessageCallback>||
std::is_same_v<T, SharedPtrWithInfoROSMessageCallback>)
{
callback(std::move(message), message_info);
if constexpr (is_ta) {
callback(convert_custom_type_to_ros_message_unique_ptr(*message), message_info);
} else {
callback(std::move(message), message_info);
}
} else if constexpr ( // NOLINT[readability/braces]
std::is_same_v<T, SharedConstPtrROSMessageCallback>||
std::is_same_v<T, ConstRefSharedConstPtrROSMessageCallback>)
{
callback(std::move(message));
if constexpr (is_ta) {
callback(convert_custom_type_to_ros_message_unique_ptr(*message));
} else {
callback(std::move(message));
}
} else if constexpr ( // NOLINT[readability/braces]
std::is_same_v<T, SharedConstPtrWithInfoROSMessageCallback>||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoROSMessageCallback>)
{
callback(std::move(message), message_info);
if constexpr (is_ta) {
callback(convert_custom_type_to_ros_message_unique_ptr(*message), message_info);
} else {
callback(std::move(message), message_info);
}
}
// condition to catch SerializedMessage types
else if constexpr ( // NOLINT[readability/braces]
@@ -860,10 +1010,10 @@ public:
}
// condition to catch unhandled callback types
else { // NOLINT[readability/braces]
static_assert(always_false_v<T>, "unhandled callback type");
static_assert(detail::always_false_v<T>, "unhandled callback type");
}
}, callback_variant_);
TRACEPOINT(callback_end, static_cast<const void *>(this));
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
}
constexpr
@@ -886,7 +1036,13 @@ public:
std::holds_alternative<UniquePtrSerializedMessageCallback>(callback_variant_) ||
std::holds_alternative<SharedConstPtrSerializedMessageCallback>(callback_variant_) ||
std::holds_alternative<ConstRefSharedConstPtrSerializedMessageCallback>(callback_variant_) ||
std::holds_alternative<SharedPtrSerializedMessageCallback>(callback_variant_);
std::holds_alternative<SharedPtrSerializedMessageCallback>(callback_variant_) ||
std::holds_alternative<ConstRefSerializedMessageWithInfoCallback>(callback_variant_) ||
std::holds_alternative<UniquePtrSerializedMessageWithInfoCallback>(callback_variant_) ||
std::holds_alternative<SharedConstPtrSerializedMessageWithInfoCallback>(callback_variant_) ||
std::holds_alternative<ConstRefSharedConstPtrSerializedMessageWithInfoCallback>(
callback_variant_) ||
std::holds_alternative<SharedPtrSerializedMessageWithInfoCallback>(callback_variant_);
}
void
@@ -895,10 +1051,14 @@ public:
#ifndef TRACETOOLS_DISABLED
std::visit(
[this](auto && callback) {
TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
tracetools::get_symbol(callback));
if (TRACETOOLS_TRACEPOINT_ENABLED(rclcpp_callback_register)) {
char * symbol = tracetools::get_symbol(callback);
TRACETOOLS_DO_TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
symbol);
std::free(symbol);
}
}, callback_variant_);
#endif // TRACETOOLS_DISABLED
}
@@ -921,6 +1081,8 @@ private:
// 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_;
std::recursive_mutex callback_mutex_;
std::atomic_bool callback_disabled_{false};
SubscribedTypeAllocator subscribed_type_allocator_;
SubscribedTypeDeleter subscribed_type_deleter_;

View File

@@ -16,11 +16,14 @@
#define RCLCPP__CALLBACK_GROUP_HPP_
#include <atomic>
#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#include "rclcpp/client.hpp"
#include "rclcpp/context.hpp"
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/publisher_base.hpp"
#include "rclcpp/service.hpp"
#include "rclcpp/subscription_base.hpp"
@@ -86,6 +89,7 @@ public:
* added to the executor in either case.
*
* \param[in] group_type The type of the callback group.
* \param[in] context A weak pointer to the context associated with this callback group.
* \param[in] automatically_add_to_executor_with_node A boolean that
* determines whether a callback group is automatically added to an executor
* with the node with which it is associated.
@@ -93,51 +97,94 @@ public:
RCLCPP_PUBLIC
explicit CallbackGroup(
CallbackGroupType group_type,
const rclcpp::Context::WeakPtr & context,
bool automatically_add_to_executor_with_node = true);
/// Default destructor.
RCLCPP_PUBLIC
~CallbackGroup();
template<typename Function>
rclcpp::SubscriptionBase::SharedPtr
find_subscription_ptrs_if(Function func) const
find_subscription_ptrs_if(const Function & func) const
{
return _find_ptrs_if_impl<rclcpp::SubscriptionBase, Function>(func, subscription_ptrs_);
}
template<typename Function>
rclcpp::TimerBase::SharedPtr
find_timer_ptrs_if(Function func) const
find_timer_ptrs_if(const Function & func) const
{
return _find_ptrs_if_impl<rclcpp::TimerBase, Function>(func, timer_ptrs_);
}
template<typename Function>
rclcpp::ServiceBase::SharedPtr
find_service_ptrs_if(Function func) const
find_service_ptrs_if(const Function & func) const
{
return _find_ptrs_if_impl<rclcpp::ServiceBase, Function>(func, service_ptrs_);
}
template<typename Function>
rclcpp::ClientBase::SharedPtr
find_client_ptrs_if(Function func) const
find_client_ptrs_if(const Function & func) const
{
return _find_ptrs_if_impl<rclcpp::ClientBase, Function>(func, client_ptrs_);
}
template<typename Function>
rclcpp::Waitable::SharedPtr
find_waitable_ptrs_if(Function func) const
find_waitable_ptrs_if(const Function & func) const
{
return _find_ptrs_if_impl<rclcpp::Waitable, Function>(func, waitable_ptrs_);
}
/// Get the total number of entities in this callback group.
/**
* \return the number of entities in the callback group.
*/
RCLCPP_PUBLIC
size_t
size() const;
/// Return a reference to the 'can be taken' atomic boolean.
/**
* The resulting bool will be true in the case that no executor is currently
* using an executable entity from this group.
* The resulting bool will be false in the case that an executor is currently
* using an executable entity from this group, and the group policy doesn't
* allow a second take (eg mutual exclusion)
* \return a reference to the flag
*/
RCLCPP_PUBLIC
std::atomic_bool &
can_be_taken_from();
/// Get the group type.
/**
* \return the group type
*/
RCLCPP_PUBLIC
const CallbackGroupType &
type() const;
/// Collect all of the entity pointers contained in this callback group.
/**
* \param[in] sub_func Function to execute for each subscription
* \param[in] service_func Function to execute for each service
* \param[in] client_func Function to execute for each client
* \param[in] timer_func Function to execute for each timer
* \param[in] waitable_fuinc Function to execute for each waitable
*/
RCLCPP_PUBLIC
void
collect_all_ptrs(
const std::function<void(const rclcpp::SubscriptionBase::SharedPtr &)> & sub_func,
const std::function<void(const rclcpp::ServiceBase::SharedPtr &)> & service_func,
const std::function<void(const rclcpp::ClientBase::SharedPtr &)> & client_func,
const std::function<void(const rclcpp::TimerBase::SharedPtr &)> & timer_func,
const std::function<void(const rclcpp::Waitable::SharedPtr &)> & waitable_func) const;
/// Return a reference to the 'associated with executor' atomic boolean.
/**
* When a callback group is added to an executor this boolean is checked
@@ -163,36 +210,49 @@ public:
bool
automatically_add_to_executor_with_node() const;
/// Retrieve the guard condition used to signal changes to this callback group.
/**
* \return guard condition if it is valid, otherwise nullptr.
*/
RCLCPP_PUBLIC
rclcpp::GuardCondition::SharedPtr
get_notify_guard_condition();
/// Trigger the notify guard condition.
RCLCPP_PUBLIC
void
trigger_notify_guard_condition();
protected:
RCLCPP_DISABLE_COPY(CallbackGroup)
RCLCPP_PUBLIC
void
add_publisher(const rclcpp::PublisherBase::SharedPtr publisher_ptr);
add_publisher(const rclcpp::PublisherBase::SharedPtr & publisher_ptr);
RCLCPP_PUBLIC
void
add_subscription(const rclcpp::SubscriptionBase::SharedPtr subscription_ptr);
add_subscription(const rclcpp::SubscriptionBase::SharedPtr & subscription_ptr);
RCLCPP_PUBLIC
void
add_timer(const rclcpp::TimerBase::SharedPtr timer_ptr);
add_timer(const rclcpp::TimerBase::SharedPtr & timer_ptr);
RCLCPP_PUBLIC
void
add_service(const rclcpp::ServiceBase::SharedPtr service_ptr);
add_service(const rclcpp::ServiceBase::SharedPtr & service_ptr);
RCLCPP_PUBLIC
void
add_client(const rclcpp::ClientBase::SharedPtr client_ptr);
add_client(const rclcpp::ClientBase::SharedPtr & client_ptr);
RCLCPP_PUBLIC
void
add_waitable(const rclcpp::Waitable::SharedPtr waitable_ptr);
add_waitable(const rclcpp::Waitable::SharedPtr & waitable_ptr);
RCLCPP_PUBLIC
void
remove_waitable(const rclcpp::Waitable::SharedPtr waitable_ptr) noexcept;
remove_waitable(const rclcpp::Waitable::SharedPtr & waitable_ptr) noexcept;
CallbackGroupType type_;
// Mutex to protect the subsequent vectors of pointers.
@@ -205,11 +265,16 @@ protected:
std::vector<rclcpp::Waitable::WeakPtr> waitable_ptrs_;
std::atomic_bool can_be_taken_from_;
const bool automatically_add_to_executor_with_node_;
// defer the creation of the guard condition
std::shared_ptr<rclcpp::GuardCondition> notify_guard_condition_ = nullptr;
std::recursive_mutex notify_guard_condition_mutex_;
rclcpp::Context::WeakPtr context_;
private:
template<typename TypeT, typename Function>
typename TypeT::SharedPtr _find_ptrs_if_impl(
Function func, const std::vector<typename TypeT::WeakPtr> & vect_ptrs) const
const Function & func, const std::vector<typename TypeT::WeakPtr> & vect_ptrs) const
{
std::lock_guard<std::mutex> lock(mutex_);
for (auto & weak_ptr : vect_ptrs) {

View File

@@ -16,33 +16,40 @@
#define RCLCPP__CLIENT_HPP_
#include <atomic>
#include <functional>
#include <future>
#include <unordered_map>
#include <memory>
#include <optional> // NOLINT, cpplint doesn't think this is a cpp std header
#include <mutex>
#include <optional>
#include <sstream>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <variant> // NOLINT
#include <variant>
#include <vector>
#include "rcl/client.h"
#include "rcl/error_handling.h"
#include "rcl/event_callback.h"
#include "rcl/service_introspection.h"
#include "rcl/wait.h"
#include "rclcpp/clock.hpp"
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/expand_topic_or_service_name.hpp"
#include "rclcpp/function_traits.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/expand_topic_or_service_name.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rcutils/logging_macros.h"
#include "rmw/error_handling.h"
#include "rmw/impl/cpp/demangle.hpp"
#include "rmw/rmw.h"
namespace rclcpp
@@ -63,14 +70,6 @@ struct FutureAndRequestId
/// Allow implicit conversions to `std::future` by reference.
operator FutureT &() {return this->future;}
/// Deprecated, use the `future` member variable instead.
/**
* Allow implicit conversions to `std::future` by value.
* \deprecated
*/
[[deprecated("FutureAndRequestId: use .future instead of an implicit conversion")]]
operator FutureT() {return this->future;}
// delegate future like methods in the std::future impl_
/// See std::future::get().
@@ -108,6 +107,29 @@ struct FutureAndRequestId
/// Destructor.
~FutureAndRequestId() = default;
};
template<typename PendingRequestsT, typename AllocatorT = std::allocator<int64_t>>
size_t
prune_requests_older_than_impl(
PendingRequestsT & pending_requests,
std::mutex & pending_requests_mutex,
std::chrono::time_point<std::chrono::system_clock> time_point,
std::vector<int64_t, AllocatorT> * pruned_requests = nullptr)
{
std::lock_guard guard(pending_requests_mutex);
auto old_size = pending_requests.size();
for (auto it = pending_requests.begin(), last = pending_requests.end(); it != last; ) {
if (it->second.first < time_point) {
if (pruned_requests) {
pruned_requests->push_back(it->first);
}
it = pending_requests.erase(it);
} else {
++it;
}
}
return old_size - pending_requests.size();
}
} // namespace detail
namespace node_interfaces
@@ -123,10 +145,10 @@ public:
RCLCPP_PUBLIC
ClientBase(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph);
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr & node_graph);
RCLCPP_PUBLIC
virtual ~ClientBase();
virtual ~ClientBase() = default;
/// Take the next response for this client as a type erased pointer.
/**
@@ -199,7 +221,8 @@ public:
virtual std::shared_ptr<void> create_response() = 0;
virtual std::shared_ptr<rmw_request_id_t> create_request_header() = 0;
virtual void handle_response(
std::shared_ptr<rmw_request_id_t> request_header, std::shared_ptr<void> response) = 0;
const std::shared_ptr<rmw_request_id_t> & request_header,
const std::shared_ptr<void> & response) = 0;
/// Exchange the "in use by wait set" state for this client.
/**
@@ -215,6 +238,123 @@ public:
bool
exchange_in_use_by_wait_set_state(bool in_use_state);
/// Get the actual request publsher QoS settings, after the defaults have been determined.
/**
* The actual configuration applied when using RMW_QOS_POLICY_*_SYSTEM_DEFAULT
* can only be resolved after the creation of the client, and it
* depends on the underlying rmw implementation.
* If the underlying setting in use can't be represented in ROS terms,
* it will be set to RMW_QOS_POLICY_*_UNKNOWN.
* May throw runtime_error when an unexpected error occurs.
*
* \return The actual request publsher qos settings.
* \throws std::runtime_error if failed to get qos settings
*/
RCLCPP_PUBLIC
rclcpp::QoS
get_request_publisher_actual_qos() const;
/// Get the actual response subscription QoS settings, after the defaults have been determined.
/**
* The actual configuration applied when using RMW_QOS_POLICY_*_SYSTEM_DEFAULT
* can only be resolved after the creation of the client, and it
* depends on the underlying rmw implementation.
* If the underlying setting in use can't be represented in ROS terms,
* it will be set to RMW_QOS_POLICY_*_UNKNOWN.
* May throw runtime_error when an unexpected error occurs.
*
* \return The actual response subscription qos settings.
* \throws std::runtime_error if failed to get qos settings
*/
RCLCPP_PUBLIC
rclcpp::QoS
get_response_subscription_actual_qos() const;
/// Set a callback to be called when each new response is received.
/**
* The callback receives a size_t which is the number of responses received
* since the last time this callback was called.
* Normally this is 1, but can be > 1 if responses were received before any
* callback was set.
*
* Since this callback is called from the middleware, you should aim to make
* it fast and not blocking.
* If you need to do a lot of work or wait for some other event, you should
* spin it off to another thread, otherwise you risk blocking the middleware.
*
* Calling it again will clear any previously set callback.
*
* An exception will be thrown if the callback is not callable.
*
* This function is thread-safe.
*
* If you want more information available in the callback, like the client
* or other information, you may use a lambda with captures or std::bind.
*
* \sa rmw_client_set_on_new_response_callback
* \sa rcl_client_set_on_new_response_callback
*
* \param[in] callback functor to be called when a new response is received
*/
void
set_on_new_response_callback(const std::function<void(size_t)> & callback)
{
if (!callback) {
throw std::invalid_argument(
"The callback passed to set_on_new_response_callback "
"is not callable.");
}
auto new_callback =
[callback, this](size_t number_of_responses) {
try {
callback(number_of_responses);
} catch (const std::exception & exception) {
RCLCPP_ERROR_STREAM(
node_logger_,
"rclcpp::ClientBase@" << this <<
" caught " << rmw::impl::cpp::demangle(exception) <<
" exception in user-provided callback for the 'on new response' callback: " <<
exception.what());
} catch (...) {
RCLCPP_ERROR_STREAM(
node_logger_,
"rclcpp::ClientBase@" << this <<
" caught unhandled exception in user-provided callback " <<
"for the 'on new response' callback");
}
};
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
// Set it temporarily to the new callback, while we replace the old one.
// This two-step setting, prevents a gap where the old std::function has
// been replaced but the middleware hasn't been told about the new one yet.
set_on_new_response_callback(
rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
static_cast<const void *>(&new_callback));
// Store the std::function to keep it in scope, also overwrites the existing one.
on_new_response_callback_ = new_callback;
// Set it again, now using the permanent storage.
set_on_new_response_callback(
rclcpp::detail::cpp_callback_trampoline<
decltype(on_new_response_callback_), const void *, size_t>,
static_cast<const void *>(&on_new_response_callback_));
}
/// Unset the callback registered for new responses, if any.
void
clear_on_new_response_callback()
{
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
if (on_new_response_callback_) {
set_on_new_response_callback(nullptr, nullptr);
on_new_response_callback_ = nullptr;
}
}
protected:
RCLCPP_DISABLE_COPY(ClientBase)
@@ -230,10 +370,22 @@ protected:
const rcl_node_t *
get_rcl_node_handle() const;
RCLCPP_PUBLIC
void
set_on_new_response_callback(rcl_event_callback_t callback, const void * user_data);
rclcpp::node_interfaces::NodeGraphInterface::WeakPtr node_graph_;
std::shared_ptr<rcl_node_t> node_handle_;
std::shared_ptr<rclcpp::Context> context_;
rclcpp::Logger node_logger_;
std::recursive_mutex callback_mutex_;
// It is important to declare on_new_response_callback_ before
// client_handle_, so on destruction the client is
// destroyed first. Otherwise, the rmw client callback
// would point briefly to a destroyed function.
std::function<void(size_t)> on_new_response_callback_{nullptr};
// Declare client_handle_ after callback
std::shared_ptr<rcl_client_t> client_handle_;
std::atomic<bool> in_use_by_wait_set_{false};
@@ -277,15 +429,6 @@ public:
{
using detail::FutureAndRequestId<std::future<SharedResponse>>::FutureAndRequestId;
/// Deprecated, use `.future.share()` instead.
/**
* Allow implicit conversions to `std::shared_future` by value.
* \deprecated
*/
[[deprecated(
"FutureAndRequestId: use .future.share() instead of an implicit conversion")]]
operator SharedFuture() {return this->future.share();}
// delegate future like methods in the std::future impl_
/// See std::future::share().
@@ -331,22 +474,20 @@ public:
* \param[in] node_base NodeBaseInterface pointer that is used in part of the setup.
* \param[in] node_graph The node graph interface of the corresponding node.
* \param[in] service_name Name of the topic to publish to.
* \param[in] client_options options for the subscription.
* \param[in] client_options options for the client.
*/
Client(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr & node_graph,
const std::string & service_name,
rcl_client_options_t & client_options)
: ClientBase(node_base, node_graph)
: ClientBase(node_base, node_graph),
srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
{
using rosidl_typesupport_cpp::get_service_type_support_handle;
auto service_type_support_handle =
get_service_type_support_handle<ServiceT>();
rcl_ret_t ret = rcl_client_init(
this->get_client_handle().get(),
this->get_rcl_node_handle(),
service_type_support_handle,
srv_type_support_handle_,
service_name.c_str(),
&client_options);
if (ret != RCL_RET_OK) {
@@ -416,8 +557,8 @@ public:
*/
void
handle_response(
std::shared_ptr<rmw_request_id_t> request_header,
std::shared_ptr<void> response) override
const std::shared_ptr<rmw_request_id_t> & request_header,
const std::shared_ptr<void> & response) override
{
std::optional<CallbackInfoVariant>
optional_pending_request = this->get_and_erase_pending_request(request_header->sequence_number);
@@ -426,7 +567,7 @@ public:
}
auto & value = *optional_pending_request;
auto typed_response = std::static_pointer_cast<typename ServiceT::Response>(
std::move(response));
response);
if (std::holds_alternative<Promise>(value)) {
auto & promise = std::get<Promise>(value);
promise.set_value(std::move(typed_response));
@@ -477,7 +618,7 @@ public:
* \return a FutureAndRequestId instance.
*/
FutureAndRequestId
async_send_request(SharedRequest request)
async_send_request(const SharedRequest & request)
{
Promise promise;
auto future = promise.get_future();
@@ -512,7 +653,7 @@ public:
>::type * = nullptr
>
SharedFutureAndRequestId
async_send_request(SharedRequest request, CallbackT && cb)
async_send_request(const SharedRequest & request, CallbackT && cb)
{
Promise promise;
auto shared_future = promise.get_future().share();
@@ -543,7 +684,7 @@ public:
>::type * = nullptr
>
SharedFutureWithRequestAndRequestId
async_send_request(SharedRequest request, CallbackT && cb)
async_send_request(const SharedRequest & request, CallbackT && cb)
{
PromiseWithRequest promise;
auto shared_future = promise.get_future().share();
@@ -637,17 +778,41 @@ public:
std::chrono::time_point<std::chrono::system_clock> time_point,
std::vector<int64_t, AllocatorT> * pruned_requests = nullptr)
{
std::lock_guard guard(pending_requests_mutex_);
auto old_size = pending_requests_.size();
for (auto it = pending_requests_.begin(), last = pending_requests_.end(); it != last; ) {
if (it->second.first < time_point) {
pruned_requests->push_back(it->first);
it = pending_requests_.erase(it);
} else {
++it;
}
return detail::prune_requests_older_than_impl(
pending_requests_,
pending_requests_mutex_,
time_point,
pruned_requests);
}
/// Configure client introspection.
/**
* \param[in] clock clock to use to generate introspection timestamps
* \param[in] qos_service_event_pub QoS settings to use when creating the introspection publisher
* \param[in] introspection_state the state to set introspection to
*
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw if
* it failed to configure introspection.
*/
void
configure_introspection(
const Clock::SharedPtr & clock, const QoS & qos_service_event_pub,
rcl_service_introspection_state_t introspection_state)
{
rcl_publisher_options_t pub_opts = rcl_publisher_get_default_options();
pub_opts.qos = qos_service_event_pub.get_rmw_qos_profile();
rcl_ret_t ret = rcl_client_configure_service_introspection(
client_handle_.get(),
node_handle_.get(),
clock->get_clock_handle(),
srv_type_support_handle_,
pub_opts,
introspection_state);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure client introspection");
}
return old_size - pending_requests_.size();
}
protected:
@@ -664,16 +829,14 @@ protected:
async_send_request_impl(const Request & request, CallbackInfoVariant value)
{
int64_t sequence_number;
std::lock_guard<std::mutex> lock(pending_requests_mutex_);
rcl_ret_t ret = rcl_send_request(get_client_handle().get(), &request, &sequence_number);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to send request");
}
{
std::lock_guard<std::mutex> lock(pending_requests_mutex_);
pending_requests_.try_emplace(
sequence_number,
std::make_pair(std::chrono::system_clock::now(), std::move(value)));
}
pending_requests_.try_emplace(
sequence_number,
std::make_pair(std::chrono::system_clock::now(), std::move(value)));
return sequence_number;
}
@@ -688,7 +851,7 @@ protected:
"Received invalid sequence number. Ignoring...");
return std::nullopt;
}
auto value = std::move(it->second.second);
std::optional<CallbackInfoVariant> value = std::move(it->second.second);
this->pending_requests_.erase(request_number);
return value;
}
@@ -702,6 +865,9 @@ protected:
CallbackInfoVariant>>
pending_requests_;
std::mutex pending_requests_mutex_;
private:
const rosidl_service_type_support_t * srv_type_support_handle_;
};
} // namespace rclcpp

View File

@@ -19,6 +19,7 @@
#include <memory>
#include <mutex>
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/time.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -59,6 +60,13 @@ public:
/**
* Initializes the clock instance with the given clock_type.
*
* WARNING Don't instantiate a clock using RCL_ROS_TIME directly,
* unless you really know what you are doing. By default no TimeSource
* is attached to a new clock. This will lead to the unexpected behavior,
* that your RCL_ROS_TIME will run always on system time. If you want
* a RCL_ROS_TIME use Node::get_clock(), or make sure to attach a
* TimeSource yourself.
*
* \param clock_type type of the clock.
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
*/
@@ -76,7 +84,110 @@ public:
*/
RCLCPP_PUBLIC
Time
now();
now() const;
/**
* Sleep until a specified Time, according to clock type.
*
* Notes for RCL_ROS_TIME clock type:
* - Can sleep forever if ros time is active and received clock never reaches `until`
* - If ROS time enabled state changes during the sleep, this method will immediately return
* false. There is not a consistent choice of sleeping time when the time source changes,
* so this is up to the caller to call again if needed.
*
* \warning When using gcc < 10 or when using gcc >= 10 and pthreads lacks the function
* `pthread_cond_clockwait`, steady clocks may sleep using the system clock.
* If so, steady clock sleep times can be affected by system clock time jumps.
* Depending on the steady clock's epoch and resolution in comparison to the system clock's,
* an overflow when converting steady clock durations to system clock times may cause
* undefined behavior.
* For more info see these issues:
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=41861
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58931
*
* \param until absolute time according to current clock type to sleep until.
* \param context the rclcpp context the clock should use to check that ROS is still initialized.
* \return true immediately if `until` is in the past
* \return true when the time `until` is reached
* \return false if time cannot be reached reliably, for example from shutdown or a change
* of time source.
* \throws std::runtime_error if the context is invalid
* \throws std::runtime_error if `until` has a different clock type from this clock
*/
RCLCPP_PUBLIC
bool
sleep_until(
const Time & until,
const Context::SharedPtr & context = contexts::get_global_default_context());
/**
* Sleep for a specified Duration.
*
* Equivalent to
*
* ```cpp
* clock->sleep_until(clock->now() + rel_time, context)
* ```
*
* The function will return immediately if `rel_time` is zero or negative.
*
* \param rel_time the length of time to sleep for.
* \param context the rclcpp context the clock should use to check that ROS is still initialized.
* \return true when the end time is reached
* \return false if time cannot be reached reliably, for example from shutdown or a change
* of time source.
* \throws std::runtime_error if the context is invalid
*/
RCLCPP_PUBLIC
bool
sleep_for(
const Duration & rel_time,
const Context::SharedPtr & context = contexts::get_global_default_context());
/**
* Check if the clock is started.
*
* A started clock is a clock that reflects non-zero time.
* Typically a clock will be unstarted if it is using RCL_ROS_TIME with ROS time and
* nothing has been published on the clock topic yet.
*
* \return true if clock is started
* \throws std::runtime_error if the clock is not rcl_clock_valid
*/
RCLCPP_PUBLIC
bool
started();
/**
* Wait until clock to start.
*
* \rclcpp::Clock::started
* \param context the context to wait in
* \return true if clock was already started or became started
* \throws std::runtime_error if the context is invalid or clock is not rcl_clock_valid
*/
RCLCPP_PUBLIC
bool
wait_until_started(const Context::SharedPtr & context = contexts::get_global_default_context());
/**
* Wait for clock to start, with timeout.
*
* The timeout is waited in steady time.
*
* \rclcpp::Clock::started
* \param timeout the maximum time to wait for.
* \param context the context to wait in.
* \param wait_tick_ns the time to wait between each iteration of the wait loop (in nanoseconds).
* \return true if clock was or became valid
* \throws std::runtime_error if the context is invalid or clock is not rcl_clock_valid
*/
RCLCPP_PUBLIC
bool
wait_until_started(
const rclcpp::Duration & timeout,
const Context::SharedPtr & context = contexts::get_global_default_context(),
const rclcpp::Duration & wait_tick_ns = rclcpp::Duration(0, static_cast<uint32_t>(1e7)));
/**
* Returns the clock of the type `RCL_ROS_TIME` is active.
@@ -103,13 +214,13 @@ public:
std::mutex &
get_clock_mutex() noexcept;
// Add a callback to invoke if the jump threshold is exceeded.
/// Add a callback to invoke if the jump threshold is exceeded.
/**
* These callback functions must remain valid as long as the
* returned shared pointer is valid.
*
* Function will register callbacks to the callback queue. On time jump all
* callbacks will be executed whose threshold is greater then the time jump;
* callbacks will be executed whose threshold is greater than the time jump;
* The logic will first call selected pre_callbacks and then all selected
* post_callbacks.
*
@@ -118,7 +229,7 @@ public:
* \param pre_callback Must be non-throwing
* \param post_callback Must be non-throwing.
* \param threshold Callbacks will be triggered if the time jump is greater
* then the threshold.
* than the threshold.
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
* \throws std::bad_alloc if the allocation of the JumpHandler fails.
* \warning the instance of the clock must remain valid as long as any created
@@ -127,8 +238,8 @@ public:
RCLCPP_PUBLIC
JumpHandler::SharedPtr
create_jump_callback(
JumpHandler::pre_callback_t pre_callback,
JumpHandler::post_callback_t post_callback,
const JumpHandler::pre_callback_t & pre_callback,
const JumpHandler::post_callback_t & post_callback,
const rcl_jump_threshold_t & threshold);
private:
@@ -146,6 +257,117 @@ private:
std::shared_ptr<Impl> impl_;
};
/**
* A synchronization primitive, equal to std::conditional_variable,
* that works with the rclcpp::Clock.
*
* For more information on the API see https://en.cppreference.com/w/cpp/thread/condition_variable.
*
* Note, this class does not handle shutdowns, if you want to
* haven them handles as well, use ClockConditionalVariable.
*/
class ClockWaiter
{
private:
class ClockWaiterImpl;
std::unique_ptr<ClockWaiterImpl> impl_;
public:
RCLCPP_SMART_PTR_DEFINITIONS(ClockWaiter)
RCLCPP_PUBLIC
explicit ClockWaiter(const rclcpp::Clock::SharedPtr & clock);
RCLCPP_PUBLIC
~ClockWaiter();
/**
* Calling this function will block the current thread, until abs_time is reached,
* or pred returns true.
* @param lock A locked lock. The lock must be locked at call time, or this method will throw.
* The lock will be atomically released and this thread will blocked.
* @param abs_time The time until which this thread shall be blocked.
* @param pred may be called in cased of spurious wakeups, but must be called every time
* notify_one() was called. During the call to pred, the given lock will be locked.
* This method will return, if pred returns true.
*/
RCLCPP_PUBLIC
bool
wait_until(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred);
/**
* Notify the blocked thread, that it should reevaluate the wakeup condition.
* The given pred function in wait_until will be reevaluated and wait_until
* will return if it evaluates to true.
*/
RCLCPP_PUBLIC
void
notify_one();
};
/**
* A synchronization primitive, similar to std::conditional_variable,
* that works with the rclcpp::Clock.
*
* For more information on the API see https://en.cppreference.com/w/cpp/thread/condition_variable.
*
* This primitive will wake up if the context was shut down.
*/
class ClockConditionalVariable
{
class Impl;
std::unique_ptr<Impl> impl_;
public:
RCLCPP_SMART_PTR_DEFINITIONS(ClockConditionalVariable)
RCLCPP_PUBLIC
ClockConditionalVariable(
const rclcpp::Clock::SharedPtr & clock,
const rclcpp::Context::SharedPtr & context = rclcpp::contexts::get_global_default_context());
RCLCPP_PUBLIC
~ClockConditionalVariable();
/**
* Calling this function will block the current thread, until abs_time is reached,
* or pred returns true.
* @param lock A locked lock. The lock must be locked at call time, or this method will throw.
* The lock will be atomically released and this thread will blocked.
* The given lock must be created using the mutex returned my mutex().
* @param abs_time The time until which this thread shall be blocked.
* @param pred may be called in cased of spurious wakeups, but must be called every time
* notify_one() was called. During the call to pred, the given lock will be locked.
* This method will return, if pred returns true.
*
* @return true if until was reached.
*/
RCLCPP_PUBLIC
bool
wait_until(
std::unique_lock<std::mutex> & lock, const rclcpp::Time & until,
const std::function<bool ()> & pred);
/**
* Notify the blocked thread, that is should reevaluate the wakeup condition.
* E.g. the given pred function in wait_until shall be reevaluated.
*/
RCLCPP_PUBLIC
void
notify_one();
/**
* Returns the internal mutex. In order to be race free with the context shutdown,
* this mutex must be used for the wait_until call.
*/
RCLCPP_PUBLIC
std::mutex &
mutex();
};
} // namespace rclcpp
#endif // RCLCPP__CLOCK_HPP_

View File

@@ -26,6 +26,7 @@
#include <unordered_set>
#include <utility>
#include <vector>
#include <stdexcept>
#include "rcl/context.h"
#include "rcl/guard_condition.h"
@@ -36,6 +37,10 @@
namespace rclcpp
{
namespace graph_listener
{
class GraphListener;
} // namespace graph_listener
/// Thrown when init is called on an already initialized context.
class ContextAlreadyInitialized : public std::runtime_error
@@ -48,22 +53,28 @@ public:
/// Forward declare WeakContextsWrapper
class WeakContextsWrapper;
class OnShutdownCallbackHandle
class ShutdownCallbackHandle
{
friend class Context;
public:
using OnShutdownCallbackType = std::function<void ()>;
using ShutdownCallbackType = std::function<void ()>;
private:
std::weak_ptr<OnShutdownCallbackType> callback;
std::weak_ptr<ShutdownCallbackType> callback;
};
using OnShutdownCallbackHandle = ShutdownCallbackHandle;
using PreShutdownCallbackHandle = ShutdownCallbackHandle;
/// Context which encapsulates shared state between nodes and other similar entities.
/**
* A context also represents the lifecycle between init and shutdown of rclcpp.
* It is often used in conjunction with rclcpp::init, or rclcpp::init_local,
* and rclcpp::shutdown.
* Nodes may be attached to a particular context by passing to the rclcpp::Node
* constructor a rclcpp::NodeOptions instance in which the Context is set via
* rclcpp::NodeOptions::context.
* Nodes will be automatically removed from the context when destructed.
* Contexts may be shutdown by calling rclcpp::shutdown.
*/
class Context : public std::enable_shared_from_this<Context>
{
@@ -75,7 +86,7 @@ public:
* Every context which is constructed is added to a global vector of contexts,
* which is used by the signal handler to conditionally shutdown each context
* on SIGINT.
* See the shutdown_on_sigint option in the InitOptions class.
* See the shutdown_on_signal option in the InitOptions class.
*/
RCLCPP_PUBLIC
Context();
@@ -93,7 +104,7 @@ public:
* Note that this function does not setup any signal handlers, so if you want
* it to be shutdown by the signal handler, then you need to either install
* them manually with rclcpp::install_signal_handlers() or use rclcpp::init().
* In addition to installing the signal handlers, the shutdown_on_sigint
* In addition to installing the signal handlers, the shutdown_on_signal
* of the InitOptions needs to be `true` for this context to be shutdown by
* the signal handler, otherwise it will be passed over.
*
@@ -124,7 +135,7 @@ public:
void
init(
int argc,
char const * const argv[],
char const * const * argv,
const rclcpp::InitOptions & init_options = rclcpp::InitOptions());
/// Return true if the context is valid, otherwise false.
@@ -180,6 +191,11 @@ public:
*
* This function is thread-safe.
*
* Note that if you override this method, but leave shutdown to be called in
* the destruction of this base class, it will not call the overridden
* version from your base class.
* So you need to ensure you call your class's shutdown() in its destructor.
*
* \param[in] reason the description of why shutdown happened
* \return true if shutdown was successful, false if context was already shutdown
* \throw various exceptions derived from rclcpp::exceptions::RCLError, if rcl_shutdown fails
@@ -189,31 +205,7 @@ public:
bool
shutdown(const std::string & reason);
using OnShutdownCallback = OnShutdownCallbackHandle::OnShutdownCallbackType;
/// Add a on_shutdown callback to be called when shutdown is called for this context.
/**
* 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
* asynchronoulsy 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 callback passed, for convenience when storing a passed lambda
*/
RCLCPP_PUBLIC
virtual
OnShutdownCallback
on_shutdown(OnShutdownCallback callback);
using OnShutdownCallback = OnShutdownCallbackHandle::ShutdownCallbackType;
/// Add a on_shutdown callback to be called when shutdown is called for this context.
/**
@@ -231,13 +223,37 @@ public:
* 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 callback passed, for convenience when storing a passed lambda
*/
RCLCPP_PUBLIC
virtual
OnShutdownCallback
on_shutdown(const OnShutdownCallback & callback);
/// Add a on_shutdown callback to be called when shutdown is called for this context.
/**
* 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 signal 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
*/
RCLCPP_PUBLIC
virtual
OnShutdownCallbackHandle
add_on_shutdown_callback(OnShutdownCallback callback);
add_on_shutdown_callback(const OnShutdownCallback & callback);
/// Remove an registered on_shutdown callbacks.
/**
@@ -249,6 +265,33 @@ public:
bool
remove_on_shutdown_callback(const OnShutdownCallbackHandle & callback_handle);
using PreShutdownCallback = PreShutdownCallbackHandle::ShutdownCallbackType;
/// Add a pre_shutdown callback to be called before shutdown is called for this context.
/**
* These callbacks will be called in the order they are added.
*
* When shutdown occurs due to the signal handler, these callbacks are run
* asynchronously in the dedicated signal handling thread.
*
* \param[in] callback the pre_shutdown callback to be registered
* \return the created callback handle
*/
RCLCPP_PUBLIC
virtual
PreShutdownCallbackHandle
add_pre_shutdown_callback(const PreShutdownCallback & callback);
/// Remove an registered pre_shutdown callback.
/**
* \param[in] callback_handle the pre_shutdown callback handle to be removed.
* \return true if the callback is found and removed, otherwise false.
*/
RCLCPP_PUBLIC
virtual
bool
remove_pre_shutdown_callback(const PreShutdownCallbackHandle & callback_handle);
/// Return the shutdown callbacks.
/**
* Returned callbacks are a copy of the registered callbacks.
@@ -257,18 +300,30 @@ public:
std::vector<OnShutdownCallback>
get_on_shutdown_callbacks() const;
/// Return the pre-shutdown callbacks.
/**
* Returned callbacks are a copy of the registered callbacks.
*/
RCLCPP_PUBLIC
std::vector<PreShutdownCallback>
get_pre_shutdown_callbacks() const;
/// Return the internal rcl context.
RCLCPP_PUBLIC
std::shared_ptr<rcl_context_t>
get_rcl_context();
RCLCPP_PUBLIC
std::shared_ptr<rclcpp::graph_listener::GraphListener>
get_graph_listener();
/// Sleep for a given period of time or until shutdown() is called.
/**
* This function can be interrupted early if:
*
* - this context is shutdown()
* - this context is destructed (resulting in shutdown)
* - this context has shutdown_on_sigint=true and SIGINT occurs (resulting in shutdown)
* - this context has shutdown_on_signal=true and SIGINT/SIGTERM occurs (resulting in shutdown)
* - interrupt_all_sleep_for() is called
*
* \param[in] nanoseconds A std::chrono::duration representing how long to sleep for.
@@ -280,7 +335,6 @@ public:
/// Interrupt any blocking sleep_for calls, causing them to return immediately and return true.
RCLCPP_PUBLIC
virtual
void
interrupt_all_sleep_for();
@@ -313,7 +367,6 @@ protected:
// Called by constructor and destructor to clean up by finalizing the
// shutdown rcl context and preparing for a new init cycle.
RCLCPP_PUBLIC
virtual
void
clean_up();
@@ -335,16 +388,47 @@ 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<std::shared_ptr<OnShutdownCallback>> on_shutdown_callbacks_;
mutable std::recursive_mutex on_shutdown_callbacks_mutex_;
std::vector<std::shared_ptr<PreShutdownCallback>> pre_shutdown_callbacks_;
mutable std::recursive_mutex pre_shutdown_callbacks_mutex_;
/// Condition variable for timed sleep (see sleep_for).
std::condition_variable interrupt_condition_variable_;
/// Mutex for protecting the global condition variable.
std::mutex interrupt_mutex_;
/// Graph Listener which waits on graph changes for the node and is shared across nodes.
std::shared_ptr<rclcpp::graph_listener::GraphListener> graph_listener_;
/// Keep shared ownership of global vector of weak contexts
std::shared_ptr<WeakContextsWrapper> weak_contexts_;
enum class ShutdownType
{
pre_shutdown,
on_shutdown
};
using ShutdownCallback = ShutdownCallbackHandle::ShutdownCallbackType;
template<ShutdownType shutdown_type>
RCLCPP_LOCAL
ShutdownCallbackHandle
add_shutdown_callback(
const ShutdownCallback & callback);
template<ShutdownType shutdown_type>
RCLCPP_LOCAL
bool
remove_shutdown_callback(
const ShutdownCallbackHandle & callback_handle);
template<ShutdownType shutdown_type>
RCLCPP_LOCAL
std::vector<rclcpp::Context::ShutdownCallback>
get_shutdown_callback() const;
};
/// Return a copy of the list of context shared pointers.

View File

@@ -0,0 +1,82 @@
// Copyright 2023 Open Navigation LLC
//
// 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__COPY_ALL_PARAMETER_VALUES_HPP_
#define RCLCPP__COPY_ALL_PARAMETER_VALUES_HPP_
#include <string>
#include <vector>
#include "rcl_interfaces/srv/list_parameters.hpp"
#include "rcl_interfaces/msg/parameter_descriptor.hpp"
#include "rcl_interfaces/msg/set_parameters_result.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/logger.hpp"
#include "rclcpp/logging.hpp"
namespace rclcpp
{
/**
* Copy all parameters from one source node to another destination node.
* May throw exceptions if parameters from source are uninitialized or undeclared.
* \param source Node to copy parameters from
* \param destination Node to copy parameters to
* \param override_existing_params Default false. Whether to override existing destination params
* if both the source and destination contain the same parameter.
*/
template<typename NodeT1, typename NodeT2>
void
copy_all_parameter_values(
const NodeT1 & source, const NodeT2 & destination, const bool override_existing_params = false)
{
using Parameters = std::vector<rclcpp::Parameter>;
using Descriptions = std::vector<rcl_interfaces::msg::ParameterDescriptor>;
auto source_params = source->get_node_parameters_interface();
auto dest_params = destination->get_node_parameters_interface();
rclcpp::Logger logger = destination->get_node_logging_interface()->get_logger();
std::vector<std::string> param_names = source_params->list_parameters({}, 0).names;
Parameters params = source_params->get_parameters(param_names);
Descriptions descriptions = source_params->describe_parameters(param_names);
for (unsigned int idx = 0; idx != params.size(); idx++) {
if (!dest_params->has_parameter(params[idx].get_name())) {
dest_params->declare_parameter(
params[idx].get_name(), params[idx].get_parameter_value(), descriptions[idx]);
} else if (override_existing_params) {
try {
rcl_interfaces::msg::SetParametersResult result =
dest_params->set_parameters_atomically({params[idx]});
if (!result.successful) {
// Parameter update rejected or read-only
RCLCPP_WARN(
logger,
"Unable to set parameter (%s): %s!",
params[idx].get_name().c_str(), result.reason.c_str());
}
} catch (const rclcpp::exceptions::InvalidParameterTypeException & e) {
RCLCPP_WARN(
logger,
"Unable to set parameter (%s): incompatable parameter type (%s)!",
params[idx].get_name().c_str(), e.what());
}
}
}
}
} // namespace rclcpp
#endif // RCLCPP__COPY_ALL_PARAMETER_VALUES_HPP_

View File

@@ -20,13 +20,24 @@
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_services_interface.hpp"
#include "rclcpp/qos.hpp"
#include "rmw/rmw.h"
namespace rclcpp
{
/// Create a service client with a given type.
/// \internal
/**
* \param[in] node_base NodeBaseInterface implementation of the node on which
* to create the client.
* \param[in] node_graph NodeGraphInterface implementation of the node on which
* to create the client.
* \param[in] node_services NodeServicesInterface implementation of the node on
* which to create the client.
* \param[in] service_name The name on which the service is accessible.
* \param[in] qos Quality of service profile for client.
* \param[in] group Callback group to handle the reply to service calls.
* \return Shared pointer to the created client.
*/
template<typename ServiceT>
typename rclcpp::Client<ServiceT>::SharedPtr
create_client(
@@ -34,11 +45,11 @@ create_client(
std::shared_ptr<node_interfaces::NodeGraphInterface> node_graph,
std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
const std::string & service_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group)
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr)
{
rcl_client_options_t options = rcl_client_get_default_options();
options.qos = qos_profile;
options.qos = qos.get_rmw_qos_profile();
auto cli = rclcpp::Client<ServiceT>::make_shared(
node_base.get(),
@@ -50,7 +61,6 @@ create_client(
node_services->add_client(cli_base_ptr, group);
return cli;
}
} // namespace rclcpp
#endif // RCLCPP__CREATE_CLIENT_HPP_

View File

@@ -0,0 +1,90 @@
// Copyright 2023 Sony Group 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__CREATE_GENERIC_CLIENT_HPP_
#define RCLCPP__CREATE_GENERIC_CLIENT_HPP_
#include <memory>
#include <string>
#include "rclcpp/generic_client.hpp"
#include "rclcpp/node_interfaces/get_node_base_interface.hpp"
#include "rclcpp/node_interfaces/get_node_graph_interface.hpp"
#include "rclcpp/node_interfaces/get_node_services_interface.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
#include "rclcpp/node_interfaces/node_services_interface.hpp"
#include "rclcpp/qos.hpp"
namespace rclcpp
{
/// Create a generic service client with a name of given type.
/**
* \param[in] node_base NodeBaseInterface implementation of the node on which
* to create the client.
* \param[in] node_graph NodeGraphInterface implementation of the node on which
* to create the client.
* \param[in] node_services NodeServicesInterface implementation of the node on
* which to create the client.
* \param[in] service_name The name on which the service is accessible.
* \param[in] service_type The name of service type, e.g. "test_msgs/srv/BasicTypes"
* \param[in] qos Quality of service profile for client.
* \param[in] group Callback group to handle the reply to service calls.
* \return Shared pointer to the created client.
*/
RCLCPP_PUBLIC
rclcpp::GenericClient::SharedPtr
create_generic_client(
const std::shared_ptr<node_interfaces::NodeBaseInterface> & node_base,
const std::shared_ptr<node_interfaces::NodeGraphInterface> & node_graph,
const std::shared_ptr<node_interfaces::NodeServicesInterface> & node_services,
const std::string & service_name,
const std::string & service_type,
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
const rclcpp::CallbackGroup::SharedPtr & group = rclcpp::CallbackGroup::SharedPtr());
/// Create a generic service client with a name of given type.
/**
* The NodeT type needs to have NodeBaseInterface implementation, NodeGraphInterface implementation
* and NodeServicesInterface implementation of the node which to create the client.
*
* \param[in] node The node on which to create the client.
* \param[in] service_name The name on which the service is accessible.
* \param[in] service_type The name of service type, e.g. "test_msgs/srv/BasicTypes"
* \param[in] qos Quality of service profile for client.
* \param[in] group Callback group to handle the reply to service calls.
* \return Shared pointer to the created client.
*/
template<typename NodeT>
rclcpp::GenericClient::SharedPtr
create_generic_client(
NodeT node,
const std::string & service_name,
const std::string & service_type,
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr)
{
return create_generic_client(
rclcpp::node_interfaces::get_node_base_interface(node),
rclcpp::node_interfaces::get_node_graph_interface(node),
rclcpp::node_interfaces::get_node_services_interface(node),
service_name,
service_type,
qos,
group
);
}
} // namespace rclcpp
#endif // RCLCPP__CREATE_GENERIC_CLIENT_HPP_

View File

@@ -0,0 +1,102 @@
// Copyright 2024 Sony Group 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__CREATE_GENERIC_SERVICE_HPP_
#define RCLCPP__CREATE_GENERIC_SERVICE_HPP_
#include <memory>
#include <string>
#include <utility>
#include "rclcpp/generic_service.hpp"
#include "rclcpp/node_interfaces/get_node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/get_node_services_interface.hpp"
#include "rclcpp/node_interfaces/node_services_interface.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rmw/rmw.h"
namespace rclcpp
{
/// Create a generic service with a given type.
/**
* \param[in] node_base NodeBaseInterface implementation of the node on which
* to create the generic service.
* \param[in] node_services NodeServicesInterface implementation of the node on
* which to create the service.
* \param[in] service_name The name on which the service is accessible.
* \param[in] service_type The name of service type, e.g. "std_srvs/srv/SetBool".
* \param[in] callback The callback to call when the service gets a request.
* \param[in] qos Quality of service profile for the service.
* \param[in] group Callback group to handle the reply to service calls.
* \return Shared pointer to the created service.
*/
template<typename CallbackT>
typename rclcpp::GenericService::SharedPtr
create_generic_service(
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
const std::string & service_name,
const std::string & service_type,
CallbackT && callback,
const rclcpp::QoS & qos,
rclcpp::CallbackGroup::SharedPtr group)
{
rclcpp::GenericServiceCallback any_service_callback;
any_service_callback.set(std::forward<CallbackT>(callback));
rcl_service_options_t service_options = rcl_service_get_default_options();
service_options.qos = qos.get_rmw_qos_profile();
auto serv = GenericService::make_shared(
node_base->get_shared_rcl_node_handle(),
service_name, service_type, any_service_callback, service_options);
auto serv_base_ptr = std::dynamic_pointer_cast<ServiceBase>(serv);
node_services->add_service(serv_base_ptr, group);
return serv;
}
/// Create a generic service with a given type.
/**
* The NodeT type needs to have NodeBaseInterface implementation and NodeServicesInterface
* implementation of the node which to create the generic service.
*
* \param[in] node The node on which to create the generic service.
* \param[in] service_name The name on which the service is accessible.
* \param[in] service_type The name of service type, e.g. "std_srvs/srv/SetBool".
* \param[in] callback The callback to call when the service gets a request.
* \param[in] qos Quality of service profile for the service.
* \param[in] group Callback group to handle the reply to service calls.
* \return Shared pointer to the created service.
*/
template<typename NodeT, typename CallbackT>
typename rclcpp::GenericService::SharedPtr
create_generic_service(
NodeT node,
const std::string & service_name,
const std::string & service_type,
CallbackT && callback,
const rclcpp::QoS & qos,
rclcpp::CallbackGroup::SharedPtr group)
{
return create_generic_service<CallbackT>(
rclcpp::node_interfaces::get_node_base_interface(node),
rclcpp::node_interfaces::get_node_services_interface(node),
service_name,
service_type,
std::forward<CallbackT>(callback), qos.get_rmw_qos_profile(), group);
}
} // namespace rclcpp
#endif // RCLCPP__CREATE_GENERIC_SERVICE_HPP_

View File

@@ -45,13 +45,15 @@ namespace rclcpp
* 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>>
template<
typename CallbackT,
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,
CallbackT && callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
)
@@ -60,13 +62,20 @@ std::shared_ptr<GenericSubscription> create_generic_subscription(
auto ts_lib = rclcpp::get_typesupport_library(
topic_type, "rosidl_typesupport_cpp");
auto allocator = options.get_allocator();
using rclcpp::AnySubscriptionCallback;
AnySubscriptionCallback<rclcpp::SerializedMessage, AllocatorT>
any_subscription_callback(*allocator);
any_subscription_callback.set(std::forward<CallbackT>(callback));
auto subscription = std::make_shared<GenericSubscription>(
topics_interface->get_node_base_interface(),
std::move(ts_lib),
topic_name,
topic_type,
qos,
callback,
any_subscription_callback,
options);
topics_interface->add_subscription(subscription, options.callback_group);

View File

@@ -92,7 +92,7 @@ template<
typename NodeT>
std::shared_ptr<PublisherT>
create_publisher(
NodeT & node,
NodeT && node,
const std::string & topic_name,
const rclcpp::QoS & qos,
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options = (

View File

@@ -26,6 +26,32 @@
namespace rclcpp
{
/// Create a service with a given type.
/**
* \param[in] node_base NodeBaseInterface implementation of the node on which
* to create the service.
* \param[in] node_services NodeServicesInterface implementation of the node on
* which to create the service.
* \param[in] service_name The name on which the service is accessible.
* \param[in] callback The callback to call when the service gets a request.
* \param[in] qos Quality of service profile for the service.
* \param[in] group Callback group to handle the reply to service calls.
* \return Shared pointer to the created service.
*/
template<typename ServiceT, typename CallbackT>
typename rclcpp::Service<ServiceT>::SharedPtr
create_service(
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
const std::string & service_name,
CallbackT && callback,
const rclcpp::QoS & qos,
rclcpp::CallbackGroup::SharedPtr group)
{
return create_service<ServiceT, CallbackT>(
node_base, node_services, service_name,
std::forward<CallbackT>(callback), qos.get_rmw_qos_profile(), group);
}
/// Create a service with a given type.
/// \internal

View File

@@ -50,8 +50,8 @@ template<
typename SubscriptionT,
typename MessageMemoryStrategyT,
typename NodeParametersT,
typename NodeTopicsT,
typename ROSMessageType = typename SubscriptionT::ROSMessageType>
typename NodeTopicsT
>
typename std::shared_ptr<SubscriptionT>
create_subscription(
NodeParametersT & node_parameters,
@@ -70,7 +70,7 @@ create_subscription(
using rclcpp::node_interfaces::get_node_topics_interface;
auto node_topics_interface = get_node_topics_interface(node_topics);
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>>
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics>
subscription_topic_stats = nullptr;
if (rclcpp::detail::resolve_enable_topic_statistics(
@@ -80,8 +80,7 @@ create_subscription(
if (options.topic_stats_options.publish_period <= std::chrono::milliseconds(0)) {
throw std::invalid_argument(
"topic_stats_options.publish_period must be greater than 0, specified value of " +
std::to_string(options.topic_stats_options.publish_period.count()) +
" ms");
std::to_string(options.topic_stats_options.publish_period.count()) + " ms");
}
std::shared_ptr<Publisher<statistics_msgs::msg::MetricsMessage>>
@@ -89,14 +88,14 @@ create_subscription(
node_parameters,
node_topics_interface,
options.topic_stats_options.publish_topic,
qos);
options.topic_stats_options.qos);
subscription_topic_stats = std::make_shared<
rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>
>(node_topics_interface->get_node_base_interface()->get_name(), publisher);
subscription_topic_stats =
std::make_shared<rclcpp::topic_statistics::SubscriptionTopicStatistics>(
node_topics_interface->get_node_base_interface()->get_name(), publisher);
std::weak_ptr<
rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>
rclcpp::topic_statistics::SubscriptionTopicStatistics
> weak_subscription_topic_stats(subscription_topic_stats);
auto sub_call_back = [weak_subscription_topic_stats]() {
auto subscription_topic_stats = weak_subscription_topic_stats.lock();

View File

@@ -23,85 +23,29 @@
#include "rclcpp/duration.hpp"
#include "rclcpp/node_interfaces/get_node_base_interface.hpp"
#include "rclcpp/node_interfaces/get_node_clock_interface.hpp"
#include "rclcpp/node_interfaces/get_node_timers_interface.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_clock_interface.hpp"
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
namespace rclcpp
{
/// Create a timer with a given clock
/// \internal
template<typename CallbackT>
typename rclcpp::TimerBase::SharedPtr
create_timer(
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
std::shared_ptr<node_interfaces::NodeTimersInterface> node_timers,
rclcpp::Clock::SharedPtr clock,
rclcpp::Duration period,
CallbackT && callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
namespace detail
{
auto timer = rclcpp::GenericTimer<CallbackT>::make_shared(
clock,
period.to_chrono<std::chrono::nanoseconds>(),
std::forward<CallbackT>(callback),
node_base->get_context());
node_timers->add_timer(timer, group);
return timer;
}
/// Create a timer with a given clock
template<typename NodeT, typename CallbackT>
typename rclcpp::TimerBase::SharedPtr
create_timer(
NodeT node,
rclcpp::Clock::SharedPtr clock,
rclcpp::Duration period,
CallbackT && callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
{
return create_timer(
rclcpp::node_interfaces::get_node_base_interface(node),
rclcpp::node_interfaces::get_node_timers_interface(node),
clock,
period,
std::forward<CallbackT>(callback),
group);
}
/// Convenience method to create a timer with node resources.
/// Perform a safe cast to a timer period in nanoseconds
/**
*
* \tparam DurationRepT
* \tparam DurationT
* \tparam CallbackT
* \param period period to execute callback. This duration must be 0 <= period < nanoseconds::max()
* \param callback callback to execute via the timer period
* \param group
* \param node_base
* \param node_timers
* \return
* \throws std::invalid argument if either node_base or node_timers
* are null, or period is negative or too large
* \return period, expressed as chrono::duration::nanoseconds
* \throws std::invalid_argument if period is negative or too large
*/
template<typename DurationRepT, typename DurationT, typename CallbackT>
typename rclcpp::WallTimer<CallbackT>::SharedPtr
create_wall_timer(
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group,
node_interfaces::NodeBaseInterface * node_base,
node_interfaces::NodeTimersInterface * node_timers)
template<typename DurationRepT, typename DurationT>
std::chrono::nanoseconds
safe_cast_to_period_in_ns(std::chrono::duration<DurationRepT, DurationT> period)
{
if (node_base == nullptr) {
throw std::invalid_argument{"input node_base cannot be null"};
}
if (node_timers == nullptr) {
throw std::invalid_argument{"input node_timers cannot be null"};
}
if (period < std::chrono::duration<DurationRepT, DurationT>::zero()) {
throw std::invalid_argument{"timer period cannot be negative"};
}
@@ -132,12 +76,142 @@ create_wall_timer(
"Casting timer period to nanoseconds resulted in integer overflow."};
}
auto timer = rclcpp::WallTimer<CallbackT>::make_shared(
period_ns, std::move(callback), node_base->get_context());
return period_ns;
}
} // namespace detail
/// Create a timer with a given clock
/// \internal
template<typename CallbackT>
typename rclcpp::TimerBase::SharedPtr
create_timer(
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
std::shared_ptr<node_interfaces::NodeTimersInterface> node_timers,
rclcpp::Clock::SharedPtr clock,
rclcpp::Duration period,
CallbackT && callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr,
bool autostart = true)
{
return create_timer(
clock,
period.to_chrono<std::chrono::nanoseconds>(),
std::forward<CallbackT>(callback),
group,
node_base.get(),
node_timers.get(),
autostart);
}
/// Create a timer with a given clock
template<typename NodeT, typename CallbackT>
typename rclcpp::TimerBase::SharedPtr
create_timer(
NodeT node,
rclcpp::Clock::SharedPtr clock,
rclcpp::Duration period,
CallbackT && callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr,
bool autostart = true)
{
return create_timer(
clock,
period.to_chrono<std::chrono::nanoseconds>(),
std::forward<CallbackT>(callback),
group,
rclcpp::node_interfaces::get_node_base_interface(node).get(),
rclcpp::node_interfaces::get_node_timers_interface(node).get(),
autostart);
}
/// Convenience method to create a general timer with node resources.
/**
*
* \tparam DurationRepT
* \tparam DurationT
* \tparam CallbackT
* \param clock clock to be used
* \param period period to execute callback. This duration must be 0 <= period < nanoseconds::max()
* \param callback callback to execute via the timer period
* \param group callback group
* \param node_base node base interface
* \param node_timers node timer interface
* \param autostart defines if the timer should start it's countdown on initialization or not.
* \return shared pointer to a generic timer
* \throws std::invalid_argument if either clock, node_base or node_timers
* are nullptr, or period is negative or too large
*/
template<typename DurationRepT, typename DurationT, typename CallbackT>
typename rclcpp::GenericTimer<CallbackT>::SharedPtr
create_timer(
rclcpp::Clock::SharedPtr clock,
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group,
node_interfaces::NodeBaseInterface * node_base,
node_interfaces::NodeTimersInterface * node_timers,
bool autostart = true)
{
if (clock == nullptr) {
throw std::invalid_argument{"clock cannot be null"};
}
if (node_base == nullptr) {
throw std::invalid_argument{"input node_base cannot be null"};
}
if (node_timers == nullptr) {
throw std::invalid_argument{"input node_timers cannot be null"};
}
const std::chrono::nanoseconds period_ns = detail::safe_cast_to_period_in_ns(period);
// Add a new generic timer.
auto timer = rclcpp::GenericTimer<CallbackT>::make_shared(
std::move(clock), period_ns, std::move(callback), node_base->get_context(), autostart);
node_timers->add_timer(timer, group);
return timer;
}
/// Convenience method to create a wall timer with node resources.
/**
*
* \tparam DurationRepT
* \tparam DurationT
* \tparam CallbackT
* \param period period to execute callback. This duration must be 0 <= period < nanoseconds::max()
* \param callback callback to execute via the timer period
* \param group callback group
* \param node_base node base interface
* \param node_timers node timer interface
* \return shared pointer to a wall timer
* \throws std::invalid_argument if either node_base or node_timers
* are null, or period is negative or too large
*/
template<typename DurationRepT, typename DurationT, typename CallbackT>
typename rclcpp::WallTimer<CallbackT>::SharedPtr
create_wall_timer(
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group,
node_interfaces::NodeBaseInterface * node_base,
node_interfaces::NodeTimersInterface * node_timers,
bool autostart = true)
{
if (node_base == nullptr) {
throw std::invalid_argument{"input node_base cannot be null"};
}
if (node_timers == nullptr) {
throw std::invalid_argument{"input node_timers cannot be null"};
}
const std::chrono::nanoseconds period_ns = detail::safe_cast_to_period_in_ns(period);
// Add a new wall timer.
auto timer = rclcpp::WallTimer<CallbackT>::make_shared(
period_ns, std::move(callback), node_base->get_context(), autostart);
node_timers->add_timer(timer, group);
return timer;
}
} // namespace rclcpp
#endif // RCLCPP__CREATE_TIMER_HPP_

View File

@@ -0,0 +1,39 @@
// 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__ADD_GUARD_CONDITION_TO_RCL_WAIT_SET_HPP_
#define RCLCPP__DETAIL__ADD_GUARD_CONDITION_TO_RCL_WAIT_SET_HPP_
#include "rclcpp/guard_condition.hpp"
namespace rclcpp
{
namespace detail
{
/// Adds the guard condition to a waitset
/**
* \param[in] wait_set reference to a wait set where to add the guard condition
* \param[in] guard_condition reference to the guard_condition to be added
*/
RCLCPP_PUBLIC
void
add_guard_condition_to_rcl_wait_set(
rcl_wait_set_t & wait_set,
const rclcpp::GuardCondition & guard_condition);
} // namespace detail
} // namespace rclcpp
#endif // RCLCPP__DETAIL__ADD_GUARD_CONDITION_TO_RCL_WAIT_SET_HPP_

View File

@@ -0,0 +1,70 @@
// 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__CPP_CALLBACK_TRAMPOLINE_HPP_
#define RCLCPP__DETAIL__CPP_CALLBACK_TRAMPOLINE_HPP_
#include <functional>
namespace rclcpp
{
namespace detail
{
/// Trampoline pattern for wrapping std::function into C-style callbacks.
/**
* A common pattern in C is for a function to take a function pointer and a
* void pointer for "user data" which is passed to the function pointer when it
* is called from within C.
*
* It works by using the user data pointer to store a pointer to a
* std::function instance.
* So when called from C, this function will cast the user data to the right
* std::function type and call it.
*
* This should allow you to use free functions, lambdas with and without
* captures, and various kinds of std::bind instances.
*
* The interior of this function is likely to be executed within a C runtime,
* so no exceptions should be thrown at this point, and doing so results in
* undefined behavior.
*
* \tparam UserDataRealT Declared type of the passed function
* \tparam UserDataT Deduced type based on what is passed for user data,
* usually this type is either `void *` or `const void *`.
* \tparam Args the arguments being passed to the callback
* \tparam ReturnT the return type of this function and the callback, default void
* \param user_data the function pointer, possibly type erased
* \param args the arguments to be forwarded to the callback
* \returns whatever the callback returns, if anything
*/
template<
typename UserDataRealT,
typename UserDataT,
typename ... Args,
typename ReturnT = void
>
ReturnT
cpp_callback_trampoline(UserDataT user_data, Args ... args) noexcept
{
auto & actual_callback = *static_cast<const UserDataRealT *>(user_data);
return actual_callback(args ...);
}
} // namespace detail
} // namespace rclcpp
#endif // RCLCPP__DETAIL__CPP_CALLBACK_TRAMPOLINE_HPP_

View File

@@ -97,6 +97,9 @@ declare_parameter_or_get(
rcl_interfaces::msg::ParameterDescriptor descriptor)
{
try {
// enable parameter modification to make it possible
// to declare QoS override parameters during parameter callbacks.
parameters_interface.enable_parameter_modification();
return parameters_interface.declare_parameter(
param_name, param_value, descriptor);
} catch (const rclcpp::exceptions::ParameterAlreadyDeclaredException &) {
@@ -104,6 +107,7 @@ declare_parameter_or_get(
}
}
#ifdef DOXYGEN_ONLY
/// \internal Declare QoS parameters for the given entity.
/**
* \tparam NodeT Node pointer or reference type.
@@ -116,12 +120,23 @@ declare_parameter_or_get(
* \param default_qos User provided qos. It will be used as a default for the parameters declared.
* \return qos profile based on the user provided parameter overrides.
*/
template<typename NodeT, typename EntityQosParametersTraits>
rclcpp::QoS
declare_qos_parameters(
const ::rclcpp::QosOverridingOptions & options,
NodeT & node,
const std::string & topic_name,
const ::rclcpp::QoS & default_qos,
EntityQosParametersTraits);
#else
template<typename NodeT, typename EntityQosParametersTraits>
std::enable_if_t<
rclcpp::node_interfaces::has_node_parameters_interface<
(rclcpp::node_interfaces::has_node_parameters_interface<
decltype(std::declval<typename rcpputils::remove_pointer<NodeT>::type>())>::value ||
std::is_same<typename std::decay_t<NodeT>,
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr>::value,
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr>::value),
rclcpp::QoS>
declare_qos_parameters(
const ::rclcpp::QosOverridingOptions & options,
@@ -204,6 +219,8 @@ declare_qos_parameters(
return default_qos;
}
#endif
/// \internal Helper function to get a rmw qos policy value from a string.
#define RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING( \
kind_lower, kind_upper, parameter_value, rclcpp_qos) \
@@ -253,8 +270,8 @@ apply_qos_override(
RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING(
reliability, RELIABILITY, value, qos);
break;
default:
throw std::invalid_argument{"unknown QosPolicyKind"};
case QosPolicyKind::Invalid:
throw std::invalid_argument{"invalid QosPolicyKind"};
}
}
@@ -315,9 +332,11 @@ get_default_qos_param_value(rclcpp::QosPolicyKind kind, const rclcpp::QoS & qos)
return ParameterValue(
check_if_stringified_policy_is_null(
rmw_qos_reliability_policy_to_str(rmw_qos.reliability), kind));
default:
throw std::invalid_argument{"unknown QoS policy kind"};
case QosPolicyKind::Invalid:
throw std::invalid_argument{"invalid QoS policy kind"};
}
return ParameterValue();
}
} // namespace detail

View File

@@ -29,7 +29,7 @@ template<typename OptionsT, typename NodeBaseT>
bool
resolve_enable_topic_statistics(const OptionsT & options, const NodeBaseT & node_base)
{
bool topic_stats_enabled;
bool topic_stats_enabled = false;
switch (options.topic_stats_options.state) {
case TopicStatisticsState::Enable:
topic_stats_enabled = true;

View File

@@ -47,6 +47,11 @@ resolve_intra_process_buffer_type(
return resolved_buffer_type;
}
RCLCPP_PUBLIC
rclcpp::IntraProcessBufferType
resolve_intra_process_buffer_type(
const rclcpp::IntraProcessBufferType buffer_type);
} // namespace detail
} // namespace rclcpp

View File

@@ -30,7 +30,7 @@ template<typename OptionsT, typename NodeBaseT>
bool
resolve_use_intra_process(const OptionsT & options, const NodeBaseT & node_base)
{
bool use_intra_process;
bool use_intra_process = false;
switch (options.use_intra_process_comm) {
case IntraProcessSetting::Enable:
use_intra_process = true;
@@ -43,7 +43,6 @@ resolve_use_intra_process(const OptionsT & options, const NodeBaseT & node_base)
break;
default:
throw std::runtime_error("Unrecognized IntraProcessSetting value");
break;
}
return use_intra_process;

View File

@@ -38,6 +38,7 @@ namespace detail
*
* This issue, with the lambda's, can be demonstrated with this minimal program:
*
* \code{.cpp}
* #include <functional>
* #include <memory>
*
@@ -52,6 +53,7 @@ namespace detail
* std::function<void (std::shared_ptr<int>)> cb = [](std::shared_ptr<int>){};
* f(cb);
* }
* \endcode
*
* If this program ever starts working in a future version of C++, this class
* may become redundant.

View File

@@ -0,0 +1,47 @@
// Copyright 2022 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__TEMPLATE_CONTAINS_HPP_
#define RCLCPP__DETAIL__TEMPLATE_CONTAINS_HPP_
#include <type_traits>
namespace rclcpp
{
namespace detail
{
/// Template meta-function that checks if a given T is contained in the list Us.
template<typename T, typename ... Us>
struct template_contains;
template<typename ... Args>
inline constexpr bool template_contains_v = template_contains<Args ...>::value;
template<typename T, typename NextT, typename ... Us>
struct template_contains<T, NextT, Us ...>
{
enum { value = (std::is_same_v<T, NextT>|| template_contains_v<T, Us ...>)};
};
template<typename T>
struct template_contains<T>
{
enum { value = false };
};
} // namespace detail
} // namespace rclcpp
#endif // RCLCPP__DETAIL__TEMPLATE_CONTAINS_HPP_

View File

@@ -0,0 +1,49 @@
// Copyright 2022 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__TEMPLATE_UNIQUE_HPP_
#define RCLCPP__DETAIL__TEMPLATE_UNIQUE_HPP_
#include <type_traits>
#include "rclcpp/detail/template_contains.hpp"
namespace rclcpp
{
namespace detail
{
/// Template meta-function that checks if a given list Ts contains unique types.
template<typename ... Ts>
struct template_unique;
template<typename ... Args>
inline constexpr bool template_unique_v = template_unique<Args ...>::value;
template<typename NextT, typename ... Ts>
struct template_unique<NextT, Ts ...>
{
enum { value = !template_contains_v<NextT, Ts ...>&& template_unique_v<Ts ...>};
};
template<typename T>
struct template_unique<T>
{
enum { value = true };
};
} // namespace detail
} // namespace rclcpp
#endif // RCLCPP__DETAIL__TEMPLATE_UNIQUE_HPP_

View File

@@ -30,7 +30,7 @@ namespace detail
std::vector<std::string>
get_unparsed_ros_arguments(
int argc, char const * const argv[],
int argc, char const * const * argv,
rcl_arguments_t * arguments,
rcl_allocator_t allocator);

View File

@@ -18,6 +18,7 @@
#include <chrono>
#include "builtin_interfaces/msg/duration.hpp"
#include "builtin_interfaces/msg/time.hpp"
#include "rcl/time.h"
#include "rclcpp/visibility_control.hpp"
@@ -38,13 +39,6 @@ public:
*/
Duration(int32_t seconds, uint32_t nanoseconds);
/// Construct duration from the specified nanoseconds.
[[deprecated(
"Use Duration::from_nanoseconds instead or std::chrono_literals. For example:"
"rclcpp::Duration::from_nanoseconds(int64_variable);"
"rclcpp::Duration(0ns);")]]
explicit Duration(rcl_duration_value_t nanoseconds);
/// Construct duration from the specified std::chrono::nanoseconds.
explicit Duration(std::chrono::nanoseconds nanoseconds);
@@ -99,9 +93,13 @@ public:
Duration
operator+(const rclcpp::Duration & rhs) const;
Duration & operator+=(const rclcpp::Duration & rhs);
Duration
operator-(const rclcpp::Duration & rhs) const;
Duration & operator-=(const rclcpp::Duration & rhs);
/// Get the maximum representable value.
/**
* \return the maximum representable value
@@ -113,6 +111,9 @@ public:
Duration
operator*(double scale) const;
Duration &
operator*=(double scale);
/// Get duration in nanosecods
/**
* \return the duration in nanoseconds as a rcl_duration_value_t.
@@ -158,6 +159,14 @@ private:
Duration() = default;
};
RCLCPP_PUBLIC
builtin_interfaces::msg::Time
operator+(const builtin_interfaces::msg::Time & lhs, const rclcpp::Duration & rhs);
RCLCPP_PUBLIC
builtin_interfaces::msg::Time
operator-(const builtin_interfaces::msg::Time & lhs, const rclcpp::Duration & rhs);
} // namespace rclcpp
#endif // RCLCPP__DURATION_HPP_

View File

@@ -0,0 +1,70 @@
// Copyright 2023 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__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_HPP_
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_HPP_
#include <rcl/allocator.h>
#include <rcl/types.h>
#include <rosidl_dynamic_typesupport/types.h>
#include <memory>
#include <string>
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace dynamic_typesupport
{
/// Utility wrapper class for rosidl_dynamic_typesupport_dynamic_data_t
/// STUBBED OUT
class DynamicMessage : public std::enable_shared_from_this<DynamicMessage>
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessage)
RCLCPP_PUBLIC
virtual ~DynamicMessage();
protected:
// NOTE(methylDragon):
// This is just here to extend the lifetime of the serialization support
// It isn't actually used by the builder since the builder should compose its own support
//
// ... Though ideally it should be the exact same support as the one stored in the
// DynamicSerializationSupport
DynamicSerializationSupport::SharedPtr serialization_support_;
rosidl_dynamic_typesupport_dynamic_data_t rosidl_dynamic_data_;
bool is_loaned_;
// Used for returning the loaned value, and lifetime management
DynamicMessage::SharedPtr parent_data_;
private:
RCLCPP_DISABLE_COPY(DynamicMessage)
RCLCPP_PUBLIC
DynamicMessage();
};
} // namespace dynamic_typesupport
} // namespace rclcpp
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_HPP_

View File

@@ -0,0 +1,64 @@
// Copyright 2023 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__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_HPP_
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_HPP_
#include <rcl/allocator.h>
#include <rosidl_dynamic_typesupport/types.h>
#include <memory>
#include <string>
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace dynamic_typesupport
{
/// Utility wrapper class for `rosidl_dynamic_typesupport_dynamic_type_t`
/// STUBBED OUT
class DynamicMessageType : public std::enable_shared_from_this<DynamicMessageType>
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessageType)
RCLCPP_PUBLIC
virtual ~DynamicMessageType();
protected:
// NOTE(methylDragon):
// This is just here to extend the lifetime of the serialization support
// It isn't actually used by the builder since the builder should compose its own support
//
// ... Though ideally it should be the exact same support as the one stored in the
// `DynamicSerializationSupport`
DynamicSerializationSupport::SharedPtr serialization_support_;
rosidl_dynamic_typesupport_dynamic_type_t rosidl_dynamic_type_;
private:
RCLCPP_DISABLE_COPY(DynamicMessageType)
RCLCPP_PUBLIC
DynamicMessageType();
};
} // namespace dynamic_typesupport
} // namespace rclcpp
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_HPP_

View File

@@ -0,0 +1,65 @@
// Copyright 2023 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__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_BUILDER_HPP_
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_BUILDER_HPP_
#include <rcl/allocator.h>
#include <rosidl_dynamic_typesupport/types.h>
#include <memory>
#include <string>
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace dynamic_typesupport
{
/// Utility wrapper class for `rosidl_dynamic_typesupport_dynamic_type_builder_t *`
/// STUBBED OUT
class DynamicMessageTypeBuilder : public std::enable_shared_from_this<DynamicMessageTypeBuilder>
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessageTypeBuilder)
RCLCPP_PUBLIC
virtual ~DynamicMessageTypeBuilder();
protected:
// NOTE(methylDragon):
// This is just here to extend the lifetime of the serialization support
// It isn't actually used by the builder since the builder should compose its own support
//
// ... Though ideally it should be the exact same support as the one stored in the
// `DynamicSerializationSupport`
DynamicSerializationSupport::SharedPtr serialization_support_;
rosidl_dynamic_typesupport_dynamic_type_builder_t rosidl_dynamic_type_builder_;
private:
RCLCPP_DISABLE_COPY(DynamicMessageTypeBuilder)
RCLCPP_PUBLIC
DynamicMessageTypeBuilder();
};
} // namespace dynamic_typesupport
} // namespace rclcpp
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_BUILDER_HPP_

View File

@@ -0,0 +1,67 @@
// Copyright 2023 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__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_SUPPORT_HPP_
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_SUPPORT_HPP_
#include <rcl/allocator.h>
#include <rosidl_dynamic_typesupport/dynamic_message_type_support_struct.h>
#include <rosidl_dynamic_typesupport/types.h>
#include <rosidl_runtime_c/message_type_support_struct.h>
#include <rosidl_runtime_c/type_description/type_description__struct.h>
#include <memory>
#include <string>
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace dynamic_typesupport
{
/// Utility wrapper class for `rosidl_message_type_support_t` containing managed
/// STUBBED OUT
class DynamicMessageTypeSupport : public std::enable_shared_from_this<DynamicMessageTypeSupport>
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessageTypeSupport)
RCLCPP_PUBLIC
virtual ~DynamicMessageTypeSupport();
protected:
DynamicSerializationSupport::SharedPtr serialization_support_;
DynamicMessageType::SharedPtr dynamic_message_type_;
DynamicMessage::SharedPtr dynamic_message_;
rosidl_message_type_support_t rosidl_message_type_support_;
private:
RCLCPP_DISABLE_COPY(DynamicMessageTypeSupport)
RCLCPP_PUBLIC
DynamicMessageTypeSupport();
};
} // namespace dynamic_typesupport
} // namespace rclcpp
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_SUPPORT_HPP_

View File

@@ -0,0 +1,60 @@
// Copyright 2023 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__DYNAMIC_TYPESUPPORT__DYNAMIC_SERIALIZATION_SUPPORT_HPP_
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_SERIALIZATION_SUPPORT_HPP_
#include <rcl/allocator.h>
#include <rosidl_dynamic_typesupport/api/serialization_support.h>
#include <rosidl_dynamic_typesupport/types.h>
#include <memory>
#include <string>
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace dynamic_typesupport
{
/// Utility wrapper class for rosidl_dynamic_typesupport_serialization_support_t
class DynamicSerializationSupport : public std::enable_shared_from_this<DynamicSerializationSupport>
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicSerializationSupport)
RCLCPP_PUBLIC
explicit DynamicSerializationSupport(rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
DynamicSerializationSupport(
const std::string & serialization_library_name,
rcl_allocator_t allocator = rcl_get_default_allocator());
RCLCPP_PUBLIC
virtual ~DynamicSerializationSupport();
protected:
rosidl_dynamic_typesupport_serialization_support_t rosidl_serialization_support_;
private:
RCLCPP_DISABLE_COPY(DynamicSerializationSupport)
};
} // namespace dynamic_typesupport
} // namespace rclcpp
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_SERIALIZATION_SUPPORT_HPP_

View File

@@ -0,0 +1,376 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__EVENT_HANDLER_HPP_
#define RCLCPP__EVENT_HANDLER_HPP_
#include <atomic>
#include <functional>
#include <memory>
#include <mutex>
#include <stdexcept>
#include <string>
#include <vector>
#include "rcl/error_handling.h"
#include "rcl/event_callback.h"
#include "rmw/impl/cpp/demangle.hpp"
#include "rmw/incompatible_qos_events_statuses.h"
#include "rmw/events_statuses/incompatible_type.h"
#include "rcutils/logging_macros.h"
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/function_traits.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/waitable.hpp"
namespace rclcpp
{
using QOSDeadlineRequestedInfo = rmw_requested_deadline_missed_status_t;
using QOSDeadlineOfferedInfo = rmw_offered_deadline_missed_status_t;
using QOSLivelinessChangedInfo = rmw_liveliness_changed_status_t;
using QOSLivelinessLostInfo = rmw_liveliness_lost_status_t;
using QOSMessageLostInfo = rmw_message_lost_status_t;
using QOSOfferedIncompatibleQoSInfo = rmw_offered_qos_incompatible_event_status_t;
using QOSRequestedIncompatibleQoSInfo = rmw_requested_qos_incompatible_event_status_t;
using IncompatibleTypeInfo = rmw_incompatible_type_status_t;
using MatchedInfo = rmw_matched_status_t;
using QOSDeadlineRequestedCallbackType = std::function<void (QOSDeadlineRequestedInfo &)>;
using QOSDeadlineOfferedCallbackType = std::function<void (QOSDeadlineOfferedInfo &)>;
using QOSLivelinessChangedCallbackType = std::function<void (QOSLivelinessChangedInfo &)>;
using QOSLivelinessLostCallbackType = std::function<void (QOSLivelinessLostInfo &)>;
using QOSMessageLostCallbackType = std::function<void (QOSMessageLostInfo &)>;
using QOSOfferedIncompatibleQoSCallbackType = std::function<void (QOSOfferedIncompatibleQoSInfo &)>;
using QOSRequestedIncompatibleQoSCallbackType =
std::function<void (QOSRequestedIncompatibleQoSInfo &)>;
using IncompatibleTypeCallbackType = std::function<void (IncompatibleTypeInfo &)>;
using PublisherMatchedCallbackType = std::function<void (MatchedInfo &)>;
using SubscriptionMatchedCallbackType = std::function<void (MatchedInfo &)>;
/// Contains callbacks for various types of events a Publisher can receive from the middleware.
struct PublisherEventCallbacks
{
QOSDeadlineOfferedCallbackType deadline_callback;
QOSLivelinessLostCallbackType liveliness_callback;
QOSOfferedIncompatibleQoSCallbackType incompatible_qos_callback;
IncompatibleTypeCallbackType incompatible_type_callback;
PublisherMatchedCallbackType matched_callback;
};
/// Contains callbacks for non-message events that a Subscription can receive from the middleware.
struct SubscriptionEventCallbacks
{
QOSDeadlineRequestedCallbackType deadline_callback;
QOSLivelinessChangedCallbackType liveliness_callback;
QOSRequestedIncompatibleQoSCallbackType incompatible_qos_callback;
QOSMessageLostCallbackType message_lost_callback;
IncompatibleTypeCallbackType incompatible_type_callback;
SubscriptionMatchedCallbackType matched_callback;
};
class UnsupportedEventTypeException : public exceptions::RCLErrorBase, public std::runtime_error
{
public:
RCLCPP_PUBLIC
UnsupportedEventTypeException(
rcl_ret_t ret,
const rcl_error_state_t * error_state,
const std::string & prefix);
RCLCPP_PUBLIC
UnsupportedEventTypeException(
const exceptions::RCLErrorBase & base_exc,
const std::string & prefix);
};
class EventHandlerBase : public Waitable
{
public:
enum class EntityType : std::size_t
{
Event,
};
RCLCPP_PUBLIC
virtual ~EventHandlerBase();
RCLCPP_PUBLIC
virtual
void enable() = 0;
RCLCPP_PUBLIC
virtual
void disable() = 0;
/// Get the number of ready events
RCLCPP_PUBLIC
size_t
get_number_of_ready_events() override;
/// Add the Waitable to a wait set.
RCLCPP_PUBLIC
void
add_to_wait_set(rcl_wait_set_t & wait_set) override;
/// Check if the Waitable is ready.
RCLCPP_PUBLIC
bool
is_ready(const rcl_wait_set_t & wait_set) override;
/// Set a callback to be called when each new event instance occurs.
/**
* The callback receives a size_t which is the number of events that occurred
* since the last time this callback was called.
* Normally this is 1, but can be > 1 if events occurred before any
* callback was set.
*
* The callback also receives an int identifier argument.
* This is needed because a Waitable may be composed of several distinct entities,
* such as subscriptions, services, etc.
* The application should provide a generic callback function that will be then
* forwarded by the waitable to all of its entities.
* Before forwarding, a different value for the identifier argument will be
* bond to the function.
* This implies that the provided callback can use the identifier to behave
* differently depending on which entity triggered the waitable to become ready.
*
* Since this callback is called from the middleware, you should aim to make
* it fast and not blocking.
* If you need to do a lot of work or wait for some other event, you should
* spin it off to another thread, otherwise you risk blocking the middleware.
*
* Calling it again will clear any previously set callback.
*
* An exception will be thrown if the callback is not callable.
*
* This function is thread-safe.
*
* If you want more information available in the callback, like the qos event
* or other information, you may use a lambda with captures or std::bind.
*
* \sa rmw_event_set_callback
* \sa rcl_event_set_callback
*
* \param[in] callback functor to be called when a new event occurs
*/
void
set_on_ready_callback(std::function<void(size_t, int)> callback) override
{
if (!callback) {
throw std::invalid_argument(
"The callback passed to set_on_ready_callback "
"is not callable.");
}
// Note: we bind the int identifier argument to this waitable's entity types
auto new_callback =
[callback, this](size_t number_of_events) {
try {
callback(number_of_events, static_cast<int>(EntityType::Event));
} catch (const std::exception & exception) {
RCLCPP_ERROR_STREAM(
// TODO(wjwwood): get this class access to the node logger it is associated with
rclcpp::get_logger("rclcpp"),
"rclcpp::EventHandlerBase@" << this <<
" caught " << rmw::impl::cpp::demangle(exception) <<
" exception in user-provided callback for the 'on ready' callback: " <<
exception.what());
} catch (...) {
RCLCPP_ERROR_STREAM(
rclcpp::get_logger("rclcpp"),
"rclcpp::EventHandlerBase@" << this <<
" caught unhandled exception in user-provided callback " <<
"for the 'on ready' callback");
}
};
std::lock_guard<std::recursive_mutex> lock(on_new_event_callback_mutex_);
// Set it temporarily to the new callback, while we replace the old one.
// This two-step setting, prevents a gap where the old std::function has
// been replaced but the middleware hasn't been told about the new one yet.
set_on_new_event_callback(
rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
static_cast<const void *>(&new_callback));
// Store the std::function to keep it in scope, also overwrites the existing one.
on_new_event_callback_ = new_callback;
// Set it again, now using the permanent storage.
set_on_new_event_callback(
rclcpp::detail::cpp_callback_trampoline<
decltype(on_new_event_callback_), const void *, size_t>,
static_cast<const void *>(&on_new_event_callback_));
}
/// Unset the callback registered for new events, if any.
void
clear_on_ready_callback() override
{
std::lock_guard<std::recursive_mutex> lock(on_new_event_callback_mutex_);
if (on_new_event_callback_) {
set_on_new_event_callback(nullptr, nullptr);
on_new_event_callback_ = nullptr;
}
}
RCLCPP_PUBLIC
std::vector<std::shared_ptr<rclcpp::TimerBase>>
get_timers() const override
{
return {};
}
protected:
RCLCPP_PUBLIC
void
set_on_new_event_callback(rcl_event_callback_t callback, const void * user_data);
std::recursive_mutex on_new_event_callback_mutex_;
std::function<void(size_t)> on_new_event_callback_{nullptr};
rcl_event_t event_handle_;
size_t wait_set_event_index_;
};
template<typename EventCallbackT, typename ParentHandleT>
class EventHandler : public EventHandlerBase
{
public:
template<typename InitFuncT, typename EventTypeEnum>
EventHandler(
const EventCallbackT & callback,
InitFuncT init_func,
ParentHandleT parent_handle,
EventTypeEnum event_type)
: parent_handle_(parent_handle), event_callback_(callback)
{
event_handle_ = rcl_get_zero_initialized_event();
rcl_ret_t ret = init_func(&event_handle_, parent_handle.get(), event_type);
if (ret != RCL_RET_OK) {
if (ret == RCL_RET_UNSUPPORTED) {
UnsupportedEventTypeException exc(ret, rcl_get_error_state(), "Failed to initialize event");
rcl_reset_error();
throw exc;
} else {
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to initialize event");
}
}
}
~EventHandler()
{
// Since the rmw event listener holds a reference to the
// "on ready" callback, we need to clear it on destruction of this class.
// This clearing is not needed for other rclcpp entities like pub/subs, since
// they do own the underlying rmw entities, which are destroyed
// on their rclcpp destructors, thus no risk of dangling pointers.
clear_on_ready_callback();
}
/// Take data so that the callback cannot be scheduled again
std::shared_ptr<void>
take_data() override
{
EventCallbackInfoT callback_info;
rcl_ret_t ret = rcl_take_event(&event_handle_, &callback_info);
if (ret != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't take event info: %s", rcl_get_error_string().str);
rcl_reset_error();
return nullptr;
}
return std::static_pointer_cast<void>(std::make_shared<EventCallbackInfoT>(callback_info));
}
std::shared_ptr<void>
take_data_by_entity_id([[maybe_unused]] size_t id) override
{
return take_data();
}
/// Execute any entities of the Waitable that are ready.
void
execute(const std::shared_ptr<void> & data) override
{
std::unique_lock<std::mutex> event_callback_lock(event_callback_mutex_);
if (disabled_.load()) {
return;
}
if (!data) {
throw std::runtime_error("'data' is empty");
}
auto callback_ptr = std::static_pointer_cast<EventCallbackInfoT>(data);
event_callback_(*callback_ptr);
callback_ptr.reset();
}
/// Disable the event callback from being called when execute(..) invoked
/**
* This will also temporarily remove the on_new_event_callback from the underlying rmw layer,
* so that it is not called from the middleware while disabled.
*/
void disable() override
{
{
// Temporary remove the on_new_event_callback_ to prevent it from being called
std::lock_guard<std::recursive_mutex> on_new_event_lock(on_new_event_callback_mutex_);
if (on_new_event_callback_) {
set_on_new_event_callback(nullptr, nullptr);
}
}
std::lock_guard<std::mutex> event_callback_lock(event_callback_mutex_);
disabled_.store(true);
}
/// Enable the event callback to be called when execute(..) invoked
/**
* This will also set back the on_new_event_callback to the underlying rmw layer, if it was
* previously removed with disable().
*/
void enable() override
{
{
// Set callback again if it was previously removed in disable()
std::lock_guard<std::recursive_mutex> on_new_event_lock(on_new_event_callback_mutex_);
if (on_new_event_callback_) {
set_on_new_event_callback(
rclcpp::detail::cpp_callback_trampoline<
decltype(on_new_event_callback_), const void *, size_t>,
static_cast<const void *>(&on_new_event_callback_));
}
}
std::lock_guard<std::mutex> event_callback_lock(event_callback_mutex_);
disabled_.store(false);
}
private:
using EventCallbackInfoT = typename std::remove_reference<typename
rclcpp::function_traits::function_traits<EventCallbackT>::template argument_type<0>>::type;
ParentHandleT parent_handle_;
EventCallbackT event_callback_;
std::mutex event_callback_mutex_;
std::atomic_bool disabled_{false};
};
} // namespace rclcpp
#endif // RCLCPP__EVENT_HANDLER_HPP_

View File

@@ -100,6 +100,15 @@ public:
{}
};
class InvalidServiceTypeError : public std::runtime_error
{
public:
InvalidServiceTypeError()
: std::runtime_error("Service type is invalid.") {}
explicit InvalidServiceTypeError(const std::string & msg)
: std::runtime_error(msg) {}
};
class UnimplementedError : public std::runtime_error
{
public:
@@ -109,6 +118,8 @@ public:
: std::runtime_error(msg) {}
};
typedef void (* reset_error_function_t)();
/// Throw a C++ std::exception which was created based on an rcl error.
/**
* Passing nullptr for reset_error is safe and will avoid calling any function
@@ -129,7 +140,7 @@ throw_from_rcl_error [[noreturn]] (
rcl_ret_t ret,
const std::string & prefix = "",
const rcl_error_state_t * error_state = nullptr,
void (* reset_error)() = rcl_reset_error);
reset_error_function_t reset_error = rcl_reset_error);
/* *INDENT-ON* */
class RCLErrorBase
@@ -204,6 +215,14 @@ public:
const std::vector<std::string> unknown_ros_args;
};
/// Thrown when an unknown type is passed
class UnknownTypeError : public std::runtime_error
{
public:
explicit UnknownTypeError(const std::string & type)
: std::runtime_error("Unknown type: " + type) {}
};
/// Thrown when an invalid rclcpp::Event object or SharedPtr is encountered.
class InvalidEventError : public std::runtime_error
{
@@ -220,6 +239,14 @@ public:
: std::runtime_error("event already registered") {}
};
/// Thrown when a callback group is missing from the node, when it wants to utilize the group.
class MissingGroupNodeException : public std::runtime_error
{
public:
explicit MissingGroupNodeException(const std::string & obj_type)
: std::runtime_error("cannot create: " + obj_type + " , callback group not in node") {}
};
/// Thrown if passed parameters are inconsistent or invalid
class InvalidParametersException : public std::runtime_error
{
@@ -254,6 +281,23 @@ public:
{}
};
/// Thrown if user attempts to create an uninitialized statically typed parameter
/**
* (see https://github.com/ros2/rclcpp/issues/1691)
*/
class UninitializedStaticallyTypedParameterException : public std::runtime_error
{
public:
/// Construct an instance.
/**
* \param[in] name the name of the parameter.
*/
RCLCPP_PUBLIC
explicit UninitializedStaticallyTypedParameterException(const std::string & name)
: std::runtime_error("Statically typed parameter '" + name + "' must be initialized.")
{}
};
/// Thrown if parameter is already declared.
class ParameterAlreadyDeclaredException : public std::runtime_error
{
@@ -289,7 +333,6 @@ 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")

View File

@@ -29,28 +29,27 @@
#include "rcl/guard_condition.h"
#include "rcl/wait.h"
#include "rclcpp/executors/executor_notify_waitable.hpp"
#include "rcpputils/scope_exit.hpp"
#include "rclcpp/context.hpp"
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/executor_options.hpp"
#include "rclcpp/executors/executor_entities_collection.hpp"
#include "rclcpp/executors/executor_entities_collector.hpp"
#include "rclcpp/future_return_code.hpp"
#include "rclcpp/memory_strategies.hpp"
#include "rclcpp/memory_strategy.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/wait_set.hpp"
namespace rclcpp
{
typedef std::map<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr,
std::owner_less<rclcpp::CallbackGroup::WeakPtr>> WeakCallbackGroupsToNodesMap;
// Forward declaration is used in convenience method signature.
class Node;
class ExecutorImplementation;
/// Coordinate the order and timing of available communication tasks.
/**
@@ -103,8 +102,8 @@ public:
RCLCPP_PUBLIC
virtual void
add_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
const rclcpp::CallbackGroup::SharedPtr & group_ptr,
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr,
bool notify = true);
/// Get callback groups that belong to executor.
@@ -174,7 +173,7 @@ public:
RCLCPP_PUBLIC
virtual void
remove_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr,
const rclcpp::CallbackGroup::SharedPtr & group_ptr,
bool notify = true);
/// Add a node to the executor.
@@ -198,7 +197,9 @@ public:
*/
RCLCPP_PUBLIC
virtual void
add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify = true);
add_node(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr,
bool notify = true);
/// Convenience function which takes Node and forwards NodeBaseInterface.
/**
@@ -206,7 +207,7 @@ public:
*/
RCLCPP_PUBLIC
virtual void
add_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true);
add_node(const std::shared_ptr<rclcpp::Node> & node_ptr, bool notify = true);
/// Remove a node from the executor.
/**
@@ -226,7 +227,9 @@ public:
*/
RCLCPP_PUBLIC
virtual void
remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify = true);
remove_node(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr,
bool notify = true);
/// Convenience function which takes Node and forwards NodeBaseInterface.
/**
@@ -234,7 +237,7 @@ public:
*/
RCLCPP_PUBLIC
virtual void
remove_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true);
remove_node(const std::shared_ptr<rclcpp::Node> & node_ptr, bool notify = true);
/// Add a node to executor, execute the next available unit of work, and remove the node.
/**
@@ -246,7 +249,7 @@ public:
template<typename RepT = int64_t, typename T = std::milli>
void
spin_node_once(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node,
std::chrono::duration<RepT, T> timeout = std::chrono::duration<RepT, T>(-1))
{
return spin_node_once_nanoseconds(
@@ -259,7 +262,7 @@ public:
template<typename NodeT = rclcpp::Node, typename RepT = int64_t, typename T = std::milli>
void
spin_node_once(
std::shared_ptr<NodeT> node,
const std::shared_ptr<NodeT> & node,
std::chrono::duration<RepT, T> timeout = std::chrono::duration<RepT, T>(-1))
{
return spin_node_once_nanoseconds(
@@ -273,29 +276,63 @@ public:
* \param[in] node Shared pointer to the node to add.
*/
RCLCPP_PUBLIC
void
spin_node_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node);
virtual void
spin_node_some(const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node);
/// Convenience function which takes Node and forwards NodeBaseInterface.
RCLCPP_PUBLIC
void
spin_node_some(std::shared_ptr<rclcpp::Node> node);
virtual void
spin_node_some(const std::shared_ptr<rclcpp::Node> & node);
/// Collect work once and execute all available work, optionally within a duration.
/// Collect work once and execute all available work, optionally within a max duration.
/**
* This function can be overridden. The default implementation is suitable for a
* single-threaded model of execution.
* Adding subscriptions, timers, services, etc. with blocking callbacks will cause this function
* to block (which may have unintended consequences).
* This function can be overridden.
* The default implementation is suitable for a single-threaded model of execution.
* Adding subscriptions, timers, services, etc. with blocking or long running
* callbacks may cause the function exceed the max_duration significantly.
*
* Work that is ready to be done is collected only once, and when collecting that work
* entities which may have multiple pieces of work ready will only be executed at most
* one time.
* The reason for this is that it is not possible to tell if, for example, a ready
* subscription has only one message ready or multiple without checking again.
* Because, in order to find out if there are multiple messages, one message must
* be taken and executed before checking again if that subscription is still ready.
* However, this function only checks for ready entities to work on once,
* and so it will never execute a single entity more than once per call to this function.
* See spin_all() variants for a function that will repeatedly work on a single entity
* in a single call.
*
* If there is no work to be done when this called, it will return immediately
* because the collecting of available work is non-blocking.
* Before each piece of ready work is executed this function checks if the
* max_duration has been exceeded, and if it has it returns without starting
* the execution of the next piece of work.
*
* If a max_duration of 0 is given, then all of the collected work will be
* executed before the function returns.
*
* \param[in] max_duration The maximum amount of time to spend executing work, or 0 for no limit.
* Note that spin_some() may take longer than this time as it only returns once max_duration has
* been exceeded.
*/
RCLCPP_PUBLIC
virtual void
spin_some(std::chrono::nanoseconds max_duration = std::chrono::nanoseconds(0));
/// Add a node, complete all immediately available work exhaustively, and remove the node.
/**
* \param[in] node Shared pointer to the node to add.
*/
RCLCPP_PUBLIC
virtual void
spin_node_all(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node,
std::chrono::nanoseconds max_duration);
/// Convenience function which takes Node and forwards NodeBaseInterface.
RCLCPP_PUBLIC
virtual void
spin_node_all(const std::shared_ptr<rclcpp::Node> & node, std::chrono::nanoseconds max_duration);
/// Collect and execute work repeatedly within a duration or until no more work is available.
/**
* This function can be overridden. The default implementation is suitable for a
@@ -305,7 +342,9 @@ public:
* If the time that waitables take to be executed is longer than the period on which new waitables
* become ready, this method will execute work repeatedly until `max_duration` has elapsed.
*
* \param[in] max_duration The maximum amount of time to spend executing work. Must be positive.
* \param[in] max_duration The maximum amount of time to spend executing work, must be >= 0.
* `0` is potentially block forever until no more work is available.
* \throw std::invalid_argument if max_duration is less than 0.
* Note that spin_all() may take longer than this time as it only returns once max_duration has
* been exceeded.
*/
@@ -313,6 +352,16 @@ public:
virtual void
spin_all(std::chrono::nanoseconds max_duration);
/// Collect work once and execute the next available work, optionally within a duration.
/**
* This function can be overridden. The default implementation is suitable for
* a single-thread model of execution.
* Adding subscriptions, timers, services, etc. with blocking callbacks will cause this function
* to block (which may have unintended consequences).
* \param[in] timeout The maximum amount of time to spend waiting for work.
* `-1` is potentially block forever waiting for work.
*/
RCLCPP_PUBLIC
virtual void
spin_once(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
@@ -326,6 +375,9 @@ public:
* 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`.
* \note This method will check the future and the timeout only when the executor is woken up.
* If this future is unrelated to an executor's entity, this method will not correctly detect
* when it's completed and therefore may wait forever and never time out.
*/
template<typename FutureT, typename TimeRepT = int64_t, typename TimeT = std::milli>
FutureReturnCode
@@ -333,52 +385,12 @@ public:
const FutureT & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
// TODO(wjwwood): does not work recursively; can't call spin_node_until_future_complete
// inside a callback executed by an executor.
// Check the future before entering the while loop.
// If the future is already complete, don't try to spin.
std::future_status status = future.wait_for(std::chrono::seconds(0));
if (status == std::future_status::ready) {
return 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;
if (spinning.exchange(true)) {
throw std::runtime_error("spin_until_future_complete() called while already spinning");
}
RCPPUTILS_SCOPE_EXIT(this->spinning.store(false); );
while (rclcpp::ok(this->context_) && spinning.load()) {
// Do one item of work.
spin_once_impl(timeout_left);
// Check if the future is set, return SUCCESS if it is.
status = future.wait_for(std::chrono::seconds(0));
if (status == std::future_status::ready) {
return FutureReturnCode::SUCCESS;
return spin_until_future_complete_impl(
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout),
[&future](std::chrono::nanoseconds wait_time) {
return future.wait_for(wait_time);
}
// 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 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 FutureReturnCode::INTERRUPTED;
);
}
/// Cancel any running spin* function, causing it to return.
@@ -387,27 +399,67 @@ public:
* \throws std::runtime_error if there is an issue triggering the guard condition
*/
RCLCPP_PUBLIC
void
virtual void
cancel();
/// Support dynamic switching of the memory strategy.
/// Returns true if the executor is currently spinning.
/**
* Switching the memory strategy while the executor is spinning in another threading could have
* unintended consequences.
* \param[in] memory_strategy Shared pointer to the memory strategy to set.
* \throws std::runtime_error if memory_strategy is null
* This function can be called asynchronously from any thread.
* \return True if the executor is currently spinning.
*/
RCLCPP_PUBLIC
bool
is_spinning();
protected:
/// Constructor that will not initialize any non-trivial members.
/**
* This constructor is intended to be used by any derived executor
* that explicitly does not want to use the default implementation provided
* by this class.
*/
explicit Executor(const std::shared_ptr<rclcpp::Context> & context);
/// Add a node to executor, execute the next available unit of work, and remove the node.
/**
* Implementation of spin_node_once using std::chrono::nanoseconds
* \param[in] node Shared pointer to the node to add.
* \param[in] timeout How long to wait for work to become available. Negative values cause
* spin_node_once to block indefinitely (the default behavior). A timeout of 0 causes this
* function to be non-blocking.
*/
RCLCPP_PUBLIC
void
set_memory_strategy(memory_strategy::MemoryStrategy::SharedPtr memory_strategy);
protected:
RCLCPP_PUBLIC
void
spin_node_once_nanoseconds(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node,
std::chrono::nanoseconds timeout);
/// Spin (blocking) until the future is complete, it times out waiting, or rclcpp is interrupted.
/**
* \sa spin_until_future_complete()
* The only difference with spin_until_future_complete() is that the future's
* type is obscured through a std::function which lets you wait on it
* reguardless of type.
*
* \param[in] timeout see spin_until_future_complete() for details
* \param[in] wait_for_future function to wait on the future and get the
* status after waiting
*/
RCLCPP_PUBLIC
virtual FutureReturnCode
spin_until_future_complete_impl(
std::chrono::nanoseconds timeout,
const std::function<std::future_status(std::chrono::nanoseconds wait_time)> & wait_for_future);
/// Collect work and execute available work, optionally within a duration.
/**
* Implementation of spin_some and spin_all.
* The exhaustive flag controls if the function will re-collect available work within the duration.
*
* \param[in] max_duration The maximum amount of time to spend executing work, or 0 for no limit.
* \param[in] exhaustive when set to true, continue to collect work and execute (spin_all)
* when set to false, return when all collected work is executed (spin_some)
*/
RCLCPP_PUBLIC
void
spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive);
@@ -422,123 +474,107 @@ protected:
void
execute_any_executable(AnyExecutable & any_exec);
/// Run subscription executable.
/**
* Do necessary setup and tear-down as well as executing the subscription.
* \param[in] subscription Subscription to execute
*/
RCLCPP_PUBLIC
static void
execute_subscription(
rclcpp::SubscriptionBase::SharedPtr subscription);
RCLCPP_PUBLIC
static void
execute_timer(rclcpp::TimerBase::SharedPtr timer);
RCLCPP_PUBLIC
static void
execute_service(rclcpp::ServiceBase::SharedPtr service);
RCLCPP_PUBLIC
static void
execute_client(rclcpp::ClientBase::SharedPtr client);
const rclcpp::SubscriptionBase::SharedPtr & subscription);
/// Run timer executable.
/**
* Do necessary setup and tear-down as well as executing the timer callback.
* \param[in] timer Timer to execute
*/
RCLCPP_PUBLIC
static void
execute_timer(const rclcpp::TimerBase::SharedPtr & timer, const std::shared_ptr<void> & data_ptr);
/// Run service server executable.
/**
* Do necessary setup and tear-down as well as executing the service server callback.
* \param[in] service Service to execute
*/
RCLCPP_PUBLIC
static void
execute_service(const rclcpp::ServiceBase::SharedPtr & service);
/// Run service client executable.
/**
* Do necessary setup and tear-down as well as executing the service client callback.
* \param[in] service Service to execute
*/
RCLCPP_PUBLIC
static void
execute_client(const rclcpp::ClientBase::SharedPtr & client);
/// Gather all of the waitable entities from associated nodes and callback groups.
RCLCPP_PUBLIC
void
collect_entities();
/// Block until more work becomes avilable or timeout is reached.
/**
* Builds a set of waitable entities, which are passed to the middleware.
* After building wait set, waits on middleware to notify.
* \param[in] timeout duration to wait for new work to become available.
* \throws std::runtime_error if the wait set can be cleared
*/
RCLCPP_PUBLIC
void
wait_for_work(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
get_node_by_group(
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
rclcpp::CallbackGroup::SharedPtr group);
/// Return true if the node has been added to this executor.
/// Check for executable in ready state and populate union structure.
/**
* \param[in] node_ptr a shared pointer that points to a node base interface
* \return true if the node is associated with the executor, otherwise false
* \param[out] any_executable populated union structure of ready executable
* \return true if an executable was ready and any_executable was populated,
* otherwise false
*/
RCLCPP_PUBLIC
bool
has_node(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) const;
RCLCPP_PUBLIC
rclcpp::CallbackGroup::SharedPtr
get_group_by_timer(rclcpp::TimerBase::SharedPtr timer);
/// Add a callback group to an executor
/**
* \see rclcpp::Executor::add_callback_group
*/
RCLCPP_PUBLIC
virtual void
add_callback_group_to_map(
rclcpp::CallbackGroup::SharedPtr group_ptr,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
bool notify = true) RCPPUTILS_TSA_REQUIRES(mutex_);
/// Remove a callback group from the executor.
/**
* \see rclcpp::Executor::remove_callback_group
*/
RCLCPP_PUBLIC
virtual void
remove_callback_group_from_map(
rclcpp::CallbackGroup::SharedPtr group_ptr,
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
bool notify = true) RCPPUTILS_TSA_REQUIRES(mutex_);
RCLCPP_PUBLIC
bool
get_next_ready_executable(AnyExecutable & any_executable);
RCLCPP_PUBLIC
bool
get_next_ready_executable_from_map(
AnyExecutable & any_executable,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
/// Wait for executable in ready state and populate union structure.
/**
* If an executable is ready, it will return immediately, otherwise
* block based on the timeout for work to become ready.
*
* \param[out] any_executable populated union structure of ready executable
* \param[in] timeout duration of time to wait for work, a negative value
* (the defualt behavior), will make this function block indefinitely
* \return true if an executable was ready and any_executable was populated,
* otherwise false
*/
RCLCPP_PUBLIC
bool
get_next_executable(
AnyExecutable & any_executable,
std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
/// Add all callback groups that can be automatically added from associated nodes.
/// This function triggers a recollect of all entities that are registered to the executor.
/**
* The executor, before collecting entities, verifies if any callback group from
* nodes associated with the executor, which is not already associated to an executor,
* can be automatically added to this executor.
* This takes care of any callback group that has been added to a node but not explicitly added
* to the executor.
* It is important to note that in order for the callback groups to be automatically added to an
* executor through this function, the node of the callback groups needs to have been added
* through the `add_node` method.
* Calling this function is thread safe.
*
* \param[in] notify if true will execute a trigger that will wake up a waiting executor
*/
RCLCPP_PUBLIC
virtual void
add_callback_groups_from_nodes_associated_to_executor() RCPPUTILS_TSA_REQUIRES(mutex_);
handle_updated_entities(bool notify);
/// Spinning state, used to prevent multi threaded calls to spin and to cancel blocking spins.
std::atomic_bool spinning;
/// Guard condition for signaling the rmw layer to wake up for special events.
rcl_guard_condition_t interrupt_guard_condition_ = rcl_get_zero_initialized_guard_condition();
std::shared_ptr<rclcpp::GuardCondition> interrupt_guard_condition_;
/// Guard condition for signaling the rmw layer to wake up for system shutdown.
std::shared_ptr<rclcpp::GuardCondition> shutdown_guard_condition_;
/// Wait set for managing entities that the rmw layer waits on.
rcl_wait_set_t wait_set_ = rcl_get_zero_initialized_wait_set();
// Mutex to protect the subsequent memory_strategy_.
mutable std::mutex 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_);
/// The context associated with this executor.
std::shared_ptr<rclcpp::Context> context_;
@@ -548,33 +584,37 @@ protected:
virtual void
spin_once_impl(std::chrono::nanoseconds timeout);
typedef std::map<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr,
const rcl_guard_condition_t *,
std::owner_less<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>>
WeakNodesToGuardConditionsMap;
/// Waitable containing guard conditions controlling the executor flow.
/**
* This waitable contains the interrupt and shutdown guard condition, as well
* as the guard condition associated with each node and callback group.
* By default, if any change is detected in the monitored entities, the notify
* waitable will awake the executor and rebuild the collections.
*/
std::shared_ptr<rclcpp::executors::ExecutorNotifyWaitable> notify_waitable_;
/// maps nodes to guard conditions
WeakNodesToGuardConditionsMap
weak_nodes_to_guard_conditions_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
std::atomic_bool entities_need_rebuild_;
/// maps callback groups associated to nodes
WeakCallbackGroupsToNodesMap
weak_groups_associated_with_executor_to_nodes_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// Collector used to associate executable entities from nodes and guard conditions
rclcpp::executors::ExecutorEntitiesCollector collector_;
/// maps callback groups to nodes associated with executor
WeakCallbackGroupsToNodesMap
weak_groups_to_nodes_associated_with_executor_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// WaitSet to be waited on.
rclcpp::WaitSet wait_set_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
std::optional<rclcpp::WaitResult<rclcpp::WaitSet>> wait_result_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// maps all callback groups to nodes
WeakCallbackGroupsToNodesMap
weak_groups_to_nodes_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// Hold the current state of the collection being waited on by the waitset
rclcpp::executors::ExecutorEntitiesCollection current_collection_ RCPPUTILS_TSA_GUARDED_BY(
mutex_);
/// nodes that are associated with the executor
std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>
weak_nodes_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// Hold the current state of the notify waitable being waited on by the waitset
std::shared_ptr<rclcpp::executors::ExecutorNotifyWaitable> current_notify_waitable_
RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// shutdown callback handle registered to Context
rclcpp::OnShutdownCallbackHandle shutdown_callback_handle_;
/// Pointer to implementation
std::unique_ptr<ExecutorImplementation> impl_;
};
} // namespace rclcpp

View File

@@ -15,6 +15,8 @@
#ifndef RCLCPP__EXECUTOR_OPTIONS_HPP_
#define RCLCPP__EXECUTOR_OPTIONS_HPP_
#include <memory>
#include "rclcpp/context.hpp"
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/memory_strategies.hpp"
@@ -24,18 +26,30 @@
namespace rclcpp
{
class ExecutorOptionsImplementation;
/// Options to be passed to the executor constructor.
struct ExecutorOptions
{
ExecutorOptions()
: memory_strategy(rclcpp::memory_strategies::create_default_strategy()),
context(rclcpp::contexts::get_global_default_context()),
max_conditions(0)
{}
RCLCPP_PUBLIC
ExecutorOptions();
RCLCPP_PUBLIC
virtual ~ExecutorOptions();
RCLCPP_PUBLIC
ExecutorOptions(const ExecutorOptions &);
RCLCPP_PUBLIC
ExecutorOptions & operator=(const ExecutorOptions &);
rclcpp::memory_strategy::MemoryStrategy::SharedPtr memory_strategy;
rclcpp::Context::SharedPtr context;
size_t max_conditions;
private:
/// Pointer to implementation
std::unique_ptr<ExecutorOptionsImplementation> impl_;
};
} // namespace rclcpp

View File

@@ -20,7 +20,7 @@
#include "rclcpp/executors/multi_threaded_executor.hpp"
#include "rclcpp/executors/single_threaded_executor.hpp"
#include "rclcpp/executors/static_single_threaded_executor.hpp"
#include "rclcpp/experimental/executors/events_executor/events_executor.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -28,25 +28,95 @@
namespace rclcpp
{
/// Create a default single-threaded executor and execute any immediately available work.
/** \param[in] node_ptr Shared pointer to the node to spin. */
/**
* @brief Create a default single-threaded executor and execute all available work exhaustively.
* @param node_ptr Shared pointer to the base interface of the node to spin.
* @param max_duration max duration to spin
*
* This method is deprecated because it can lead to very bad performance if used in a loop:
* each call will create a new executor and register the node, which is an expensive operation.
* It's recommended to always manually instantiate an executor and call the methods with
* the same name on it.
* For example:
* SingleThreadedExecutor executor;
* executor.add_node(node_ptr);
* executor.spin_all(max_duration);
* If you are using a non-default context, this should be passed to the executor's constructor.
*/
[[deprecated("use SingleThreadedExecutor::spin_all instead")]]
RCLCPP_PUBLIC
void
spin_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr);
spin_all(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr,
std::chrono::nanoseconds max_duration);
/**
* @brief Create a default single-threaded executor and execute all available work exhaustively.
* @param node_ptr Shared pointer to the node to spin.
* @param max_duration max duration to spin
*
* This method is deprecated because it can lead to very bad performance if used in a loop:
* each call will create a new executor and register the node, which is an expensive operation.
* It's recommended to always manually instantiate an executor and call the methods with
* the same name on it.
* For example:
* SingleThreadedExecutor executor;
* executor.add_node(node_ptr);
* executor.spin_all(max_duration);
* If you are using a non-default context, this should be passed to the executor's constructor.
*/
[[deprecated("use SingleThreadedExecutor::spin_all instead")]]
RCLCPP_PUBLIC
void
spin_some(rclcpp::Node::SharedPtr node_ptr);
spin_all(const rclcpp::Node::SharedPtr & node_ptr, std::chrono::nanoseconds max_duration);
/**
* @brief Create a default single-threaded executor and execute any immediately available work.
* @param node_ptr Shared pointer to the base interface of the node to spin.
*
* This method is deprecated because it can lead to very bad performance if used in a loop:
* each call will create a new executor and register the node, which is an expensive operation.
* It's recommended to always manually instantiate an executor and call the methods with
* the same name on it.
* For example:
* SingleThreadedExecutor executor;
* executor.add_node(node_ptr);
* executor.spin_some();
* If you are using a non-default context, this should be passed to the executor's constructor.
*/
[[deprecated("use SingleThreadedExecutor::spin_some instead")]]
RCLCPP_PUBLIC
void
spin_some(const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr);
/**
* @brief Create a default single-threaded executor and execute any immediately available work.
* @param node_ptr Shared pointer to the node to spin.
*
* This method is deprecated because it can lead to very bad performance if used in a loop:
* each call will create a new executor and register the node, which is an expensive operation.
* It's recommended to always manually instantiate an executor and call the methods with
* the same name on it.
* For example:
* SingleThreadedExecutor executor;
* executor.add_node(node_ptr);
* executor.spin_some();
* If you are using a non-default context, this should be passed to the executor's constructor.
*/
[[deprecated("use SingleThreadedExecutor::spin_some instead")]]
RCLCPP_PUBLIC
void
spin_some(const rclcpp::Node::SharedPtr & node_ptr);
/// Create a default single-threaded executor and spin the specified node.
/** \param[in] node_ptr Shared pointer to the node to spin. */
RCLCPP_PUBLIC
void
spin(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr);
spin(const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr);
RCLCPP_PUBLIC
void
spin(rclcpp::Node::SharedPtr node_ptr);
spin(const rclcpp::Node::SharedPtr & node_ptr);
namespace executors
{
@@ -70,7 +140,7 @@ template<typename FutureT, typename TimeRepT = int64_t, typename TimeT = std::mi
rclcpp::FutureReturnCode
spin_node_until_future_complete(
rclcpp::Executor & executor,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr,
const FutureT & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
@@ -87,7 +157,7 @@ template<typename NodeT = rclcpp::Node, typename FutureT, typename TimeRepT = in
rclcpp::FutureReturnCode
spin_node_until_future_complete(
rclcpp::Executor & executor,
std::shared_ptr<NodeT> node_ptr,
const std::shared_ptr<NodeT> & node_ptr,
const FutureT & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
@@ -103,11 +173,13 @@ spin_node_until_future_complete(
template<typename FutureT, typename TimeRepT = int64_t, typename TimeT = std::milli>
rclcpp::FutureReturnCode
spin_until_future_complete(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr,
const FutureT & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
rclcpp::executors::SingleThreadedExecutor executor;
rclcpp::ExecutorOptions options;
options.context = node_ptr->get_context();
rclcpp::executors::SingleThreadedExecutor executor(options);
return executors::spin_node_until_future_complete<FutureT>(executor, node_ptr, future, timeout);
}
@@ -115,7 +187,7 @@ template<typename NodeT = rclcpp::Node, typename FutureT, typename TimeRepT = in
typename TimeT = std::milli>
rclcpp::FutureReturnCode
spin_until_future_complete(
std::shared_ptr<NodeT> node_ptr,
const std::shared_ptr<NodeT> & node_ptr,
const FutureT & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{

View File

@@ -0,0 +1,219 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__EXECUTORS__EXECUTOR_ENTITIES_COLLECTION_HPP_
#define RCLCPP__EXECUTORS__EXECUTOR_ENTITIES_COLLECTION_HPP_
#include <deque>
#include <functional>
#include <unordered_map>
#include <vector>
#include <rclcpp/any_executable.hpp>
#include <rclcpp/node_interfaces/node_base.hpp>
#include <rclcpp/callback_group.hpp>
#include <rclcpp/executors/executor_notify_waitable.hpp>
#include <rclcpp/visibility_control.hpp>
#include <rclcpp/wait_result.hpp>
#include <rclcpp/wait_set.hpp>
namespace rclcpp
{
namespace executors
{
/// Structure to represent a single entity's entry in a collection
template<typename EntityValueType>
struct CollectionEntry
{
/// Weak pointer to entity type
using EntityWeakPtr = typename EntityValueType::WeakPtr;
/// Shared pointer to entity type
using EntitySharedPtr = typename EntityValueType::SharedPtr;
/// The entity
EntityWeakPtr entity;
/// If relevant, the entity's corresponding callback_group
rclcpp::CallbackGroup::WeakPtr callback_group;
};
/// Update a collection based on another collection
/*
* Iterates update_from and update_to to see which entities have been added/removed between
* the two collections.
*
* For each new entry (in update_from, but not in update_to),
* add the entity and fire the on_added callback
* For each removed entry (in update_to, but not in update_from),
* remove the entity and fire the on_removed callback.
*
* \param[in] update_from The collection representing the next iteration's state
* \param[inout] update_to The collection representing the current iteration's state
* \param[in] on_added Callback fired when a new entity is detected
* \param[in] on_removed Callback fired when an entity is removed
*/
template<typename CollectionType>
void update_entities(
const CollectionType & update_from,
CollectionType & update_to,
std::function<void(const typename CollectionType::EntitySharedPtr &)> on_added,
std::function<void(const typename CollectionType::EntitySharedPtr &)> on_removed
)
{
for (auto it = update_to.begin(); it != update_to.end(); ) {
if (update_from.count(it->first) == 0) {
auto entity = it->second.entity.lock();
if (entity) {
on_removed(entity);
}
it = update_to.erase(it);
} else {
++it;
}
}
for (auto it = update_from.begin(); it != update_from.end(); ++it) {
if (update_to.count(it->first) == 0) {
auto entity = it->second.entity.lock();
if (entity) {
on_added(entity);
}
update_to.insert(*it);
}
}
}
/// A collection of entities, indexed by their corresponding handles
template<typename EntityKeyType, typename EntityValueType>
class EntityCollection
: public std::unordered_map<const EntityKeyType *, CollectionEntry<EntityValueType>>
{
public:
/// Key type of the map
using Key = const EntityKeyType *;
/// Weak pointer to entity type
using EntityWeakPtr = typename EntityValueType::WeakPtr;
/// Shared pointer to entity type
using EntitySharedPtr = typename EntityValueType::SharedPtr;
/// Update this collection based on the contents of another collection
/**
* Update the internal state of this collection, firing callbacks when entities have been
* added or removed.
*
* \param[in] other Collection to compare to
* \param[in] on_added Callback for when entities have been added
* \param[in] on_removed Callback for when entities have been removed
*/
void update(
const EntityCollection<EntityKeyType, EntityValueType> & other,
std::function<void(const EntitySharedPtr &)> on_added,
std::function<void(const EntitySharedPtr &)> on_removed)
{
update_entities(other, *this, on_added, on_removed);
}
};
/// Represent the total set of entities for a single executor
/**
* This allows the entities to be stored from ExecutorEntitiesCollector.
* The structure also makes in convenient to re-evaluate when entities have been added or removed.
*/
struct ExecutorEntitiesCollection
{
/// Collection type for timer entities
using TimerCollection = EntityCollection<rcl_timer_t, rclcpp::TimerBase>;
/// Collection type for subscription entities
using SubscriptionCollection = EntityCollection<rcl_subscription_t, rclcpp::SubscriptionBase>;
/// Collection type for client entities
using ClientCollection = EntityCollection<rcl_client_t, rclcpp::ClientBase>;
/// Collection type for service entities
using ServiceCollection = EntityCollection<rcl_service_t, rclcpp::ServiceBase>;
/// Collection type for waitable entities
using WaitableCollection = EntityCollection<rclcpp::Waitable, rclcpp::Waitable>;
/// Collection type for guard condition entities
using GuardConditionCollection = EntityCollection<rcl_guard_condition_t, rclcpp::GuardCondition>;
/// Collection of timers currently in use by the executor.
TimerCollection timers;
/// Collection of subscriptions currently in use by the executor.
SubscriptionCollection subscriptions;
/// Collection of clients currently in use by the executor.
ClientCollection clients;
/// Collection of services currently in use by the executor.
ServiceCollection services;
/// Collection of guard conditions currently in use by the executor.
GuardConditionCollection guard_conditions;
/// Collection of waitables currently in use by the executor.
WaitableCollection waitables;
/// Check if the entities collection is empty
/**
* \return true if all member collections are empty, false otherwise
*/
bool empty() const;
/// Clear the entities collection
void clear();
/// Remove entities that have expired weak ownership
/**
* \return The total number of removed entities
*/
size_t remove_expired_entities();
};
/// Build an entities collection from callback groups
/**
* Iterates a list of callback groups and adds entities from each valid group
*
* \param[in] callback_groups List of callback groups to check for entities
* \param[inout] colletion Entities collection to populate with found entities
*/
void
build_entities_collection(
const std::vector<rclcpp::CallbackGroup::WeakPtr> & callback_groups,
ExecutorEntitiesCollection & collection);
/// Build a queue of executables ready to be executed
/**
* Iterates a list of entities and adds them to a queue if they are ready.
*
* \param[in] collection Collection of entities corresponding to the current wait set.
* \param[in] wait_result Result of rclcpp::WaitSet::wait corresponding to the collection.
* \param[inout] queue of executables to append new ready executables to
* \return number of new ready executables
*/
size_t
ready_executables(
const ExecutorEntitiesCollection & collection,
rclcpp::WaitResult<rclcpp::WaitSet> & wait_result,
std::deque<rclcpp::AnyExecutable> & executables
);
} // namespace executors
} // namespace rclcpp
#endif // RCLCPP__EXECUTORS__EXECUTOR_ENTITIES_COLLECTION_HPP_

View File

@@ -0,0 +1,270 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__EXECUTORS__EXECUTOR_ENTITIES_COLLECTOR_HPP_
#define RCLCPP__EXECUTORS__EXECUTOR_ENTITIES_COLLECTOR_HPP_
#include <map>
#include <memory>
#include <mutex>
#include <set>
#include <vector>
#include "rcpputils/thread_safety_annotations.hpp"
#include <rclcpp/any_executable.hpp>
#include <rclcpp/node_interfaces/node_base.hpp>
#include <rclcpp/callback_group.hpp>
#include <rclcpp/executors/executor_notify_waitable.hpp>
#include <rclcpp/visibility_control.hpp>
#include <rclcpp/wait_set.hpp>
#include <rclcpp/wait_result.hpp>
namespace rclcpp
{
namespace executors
{
/// Class to monitor a set of nodes and callback groups for changes in entity membership
/**
* This is to be used with an executor to track the membership of various nodes, groups,
* and entities (timers, subscriptions, clients, services, etc) and report status to the
* executor.
*
* In general, users will add either nodes or callback groups to an executor.
* Each node may have callback groups that are automatically associated with executors,
* or callback groups that must be manually associated with an executor.
*
* This object tracks both types of callback groups as well as nodes that have been
* previously added to the executor.
* When a new callback group is added/removed or new entities are added/removed, the
* corresponding node or callback group will signal this to the executor so that the
* entity collection may be rebuilt according to that executor's implementation.
*
*/
class ExecutorEntitiesCollector
{
public:
/// Constructor
/**
* \param[in] notify_waitable Waitable that is used to signal to the executor
* when nodes or callback groups have been added or removed.
*/
RCLCPP_PUBLIC
explicit ExecutorEntitiesCollector(
const std::shared_ptr<ExecutorNotifyWaitable> & notify_waitable);
/// Destructor
RCLCPP_PUBLIC
~ExecutorEntitiesCollector();
/// Indicate if the entities collector has pending additions or removals.
/**
* \return true if there are pending additions or removals
*/
bool has_pending() const;
/// Add a node to the entity collector
/**
* \param[in] node_ptr a shared pointer that points to a node base interface
* \throw std::runtime_error if the node is associated with an executor
*/
RCLCPP_PUBLIC
void
add_node(const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr);
/// Remove a node from the entity collector
/**
* \param[in] node_ptr a shared pointer that points to a node base interface
* \throw std::runtime_error if the node is associated with an executor
* \throw std::runtime_error if the node is associated with this executor
*/
RCLCPP_PUBLIC
void
remove_node(const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr);
/// Add a callback group to the entity collector
/**
* \param[in] group_ptr a shared pointer that points to a callback group
* \throw std::runtime_error if the callback_group is associated with an executor
*/
RCLCPP_PUBLIC
void
add_callback_group(const rclcpp::CallbackGroup::SharedPtr & group_ptr);
/// Remove a callback group from the entity collector
/**
* \param[in] group_ptr a shared pointer that points to a callback group
* \throw std::runtime_error if the callback_group is not associated with an executor
* \throw std::runtime_error if the callback_group is not associated with this executor
*/
RCLCPP_PUBLIC
void
remove_callback_group(const rclcpp::CallbackGroup::SharedPtr & group_ptr);
/// Get all callback groups known to this entity collector
/**
* This will include manually added and automatically added (node associated) groups
* \return vector of all callback groups
*/
RCLCPP_PUBLIC
std::vector<rclcpp::CallbackGroup::WeakPtr>
get_all_callback_groups() const;
/// Get manually-added callback groups known to this entity collector
/**
* This will include callback groups that have been added via add_callback_group
* \return vector of manually-added callback groups
*/
RCLCPP_PUBLIC
std::vector<rclcpp::CallbackGroup::WeakPtr>
get_manually_added_callback_groups() const;
/// Get automatically-added callback groups known to this entity collector
/**
* This will include callback groups that are associated with nodes added via add_node
* \return vector of automatically-added callback groups
*/
RCLCPP_PUBLIC
std::vector<rclcpp::CallbackGroup::WeakPtr>
get_automatically_added_callback_groups() const;
/// Update the underlying collections
/**
* This will prune nodes and callback groups that are no longer valid as well
* as add new callback groups from any associated nodes.
*/
RCLCPP_PUBLIC
void
update_collections();
protected:
using NodeCollection = std::set<
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr,
std::owner_less<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>>;
using CallbackGroupCollection = std::set<
rclcpp::CallbackGroup::WeakPtr,
std::owner_less<rclcpp::CallbackGroup::WeakPtr>>;
using WeakNodesToGuardConditionsMap = std::map<
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr,
rclcpp::GuardCondition::WeakPtr,
std::owner_less<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>>;
using WeakGroupsToGuardConditionsMap = std::map<
rclcpp::CallbackGroup::WeakPtr,
rclcpp::GuardCondition::WeakPtr,
std::owner_less<rclcpp::CallbackGroup::WeakPtr>>;
/// Implementation of removing a node from the collector.
/**
* This will disassociate the node from the collector and remove any
* automatically-added callback groups
*
* This takes and returns an iterator so it may be used as:
*
* it = remove_weak_node(it);
*
* \param[in] weak_node iterator to the weak node to be removed
* \return Valid updated iterator in the same collection
*/
RCLCPP_PUBLIC
NodeCollection::iterator
remove_weak_node(NodeCollection::iterator weak_node) RCPPUTILS_TSA_REQUIRES(mutex_);
/// Implementation of removing a callback group from the collector.
/**
* This will disassociate the callback group from the collector
*
* This takes and returns an iterator so it may be used as:
*
* it = remove_weak_callback_group(it);
*
* \param[in] weak_group_it iterator to the weak group to be removed
* \param[in] collection the collection to remove the group from
* (manually or automatically added)
* \return Valid updated iterator in the same collection
*/
RCLCPP_PUBLIC
CallbackGroupCollection::iterator
remove_weak_callback_group(
CallbackGroupCollection::iterator weak_group_it,
CallbackGroupCollection & collection) RCPPUTILS_TSA_REQUIRES(mutex_);
/// Implementation of adding a callback group
/**
* \param[in] group_ptr the group to add
* \param[in] collection the collection to add the group to
*/
RCLCPP_PUBLIC
void
add_callback_group_to_collection(
const rclcpp::CallbackGroup::SharedPtr & group_ptr,
CallbackGroupCollection & collection) RCPPUTILS_TSA_REQUIRES(mutex_);
/// Iterate over queued added/remove nodes and callback_groups
RCLCPP_PUBLIC
void
process_queues() RCPPUTILS_TSA_REQUIRES(mutex_);
/// Check a collection of nodes and add any new callback_groups that
/// are set to be automatically associated via the node.
RCLCPP_PUBLIC
void
add_automatically_associated_callback_groups(
const NodeCollection & nodes_to_check) RCPPUTILS_TSA_REQUIRES(mutex_);
/// Check all nodes and group for expired weak pointers and remove them.
RCLCPP_PUBLIC
void
prune_invalid_nodes_and_groups() RCPPUTILS_TSA_REQUIRES(mutex_);
/// mutex to protect collections and pending queues
mutable std::mutex mutex_;
/// Callback groups that were added via `add_callback_group`
CallbackGroupCollection manually_added_groups_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// Callback groups that were added by their association with added nodes
CallbackGroupCollection automatically_added_groups_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// nodes that are associated with the executor
NodeCollection weak_nodes_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// Track guard conditions associated with added nodes
WeakNodesToGuardConditionsMap weak_nodes_to_guard_conditions_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// Track guard conditions associated with added callback groups
WeakGroupsToGuardConditionsMap weak_groups_to_guard_conditions_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// nodes that have been added since the last update.
NodeCollection pending_added_nodes_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// nodes that have been removed since the last update.
NodeCollection pending_removed_nodes_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// callback groups that have been added since the last update.
CallbackGroupCollection pending_manually_added_groups_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// callback groups that have been removed since the last update.
CallbackGroupCollection pending_manually_removed_groups_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// Waitable to add guard conditions to
std::shared_ptr<ExecutorNotifyWaitable> notify_waitable_;
};
} // namespace executors
} // namespace rclcpp
//
#endif // RCLCPP__EXECUTORS__EXECUTOR_ENTITIES_COLLECTOR_HPP_

View File

@@ -0,0 +1,189 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__EXECUTORS__EXECUTOR_NOTIFY_WAITABLE_HPP_
#define RCLCPP__EXECUTORS__EXECUTOR_NOTIFY_WAITABLE_HPP_
#include <functional>
#include <memory>
#include <mutex>
#include <set>
#include <vector>
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/waitable.hpp"
namespace rclcpp
{
namespace executors
{
/// Maintain a collection of guard conditions from associated nodes and callback groups
/// to signal to the executor when associated entities have changed.
class ExecutorNotifyWaitable : public rclcpp::Waitable
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(ExecutorNotifyWaitable)
// Constructor
/**
* \param[in] on_execute_callback Callback to execute when one of the conditions
* of this waitable has signaled the wait_set.
*/
RCLCPP_PUBLIC
explicit ExecutorNotifyWaitable(
const std::function<void(void)> & on_execute_callback = {},
const rclcpp::Context::SharedPtr & context =
rclcpp::contexts::get_global_default_context());
// Destructor
RCLCPP_PUBLIC
~ExecutorNotifyWaitable() override = default;
RCLCPP_PUBLIC
ExecutorNotifyWaitable(ExecutorNotifyWaitable & other);
RCLCPP_PUBLIC
ExecutorNotifyWaitable & operator=(ExecutorNotifyWaitable & other);
/// Add conditions to the wait set
/**
* \param[inout] wait_set structure that conditions will be added to
*/
RCLCPP_PUBLIC
void
add_to_wait_set(rcl_wait_set_t & wait_set) override;
/// Check conditions against the wait set
/**
* \param[inout] wait_set structure that internal elements will be checked against.
* \return true if this waitable is ready to be executed, false otherwise.
*/
RCLCPP_PUBLIC
bool
is_ready(const rcl_wait_set_t & wait_set) override;
/// Perform work associated with the waitable.
/**
* This will call the callback provided in the constructor.
* \param[in] data Data to be use for the execute, if available, else nullptr.
*/
RCLCPP_PUBLIC
void
execute(const std::shared_ptr<void> & data) override;
/// Retrieve data to be used in the next execute call.
/**
* \return If available, data to be used, otherwise nullptr
*/
RCLCPP_PUBLIC
std::shared_ptr<void>
take_data() override;
/// Take the data from an entity ID so that it can be consumed with `execute`.
/**
* \param[in] id ID of the entity to take data from.
* \return If available, data to be used, otherwise nullptr
* \sa rclcpp::Waitable::take_data_by_entity_id
*/
RCLCPP_PUBLIC
std::shared_ptr<void>
take_data_by_entity_id(size_t id) override;
/// Set a callback to be called whenever the waitable becomes ready.
/**
* \param[in] callback callback to set
* \sa rclcpp::Waitable::set_on_ready_callback
*/
RCLCPP_PUBLIC
void
set_on_ready_callback(std::function<void(size_t, int)> callback) override;
/// Add a guard condition to be waited on.
/**
* \param[in] guard_condition The guard condition to add.
*/
RCLCPP_PUBLIC
void
add_guard_condition(const rclcpp::GuardCondition::WeakPtr & guard_condition);
/// Unset any callback registered via set_on_ready_callback.
/**
* \sa rclcpp::Waitable::clear_on_ready_callback
*/
RCLCPP_PUBLIC
void
clear_on_ready_callback() override;
/// Set a new callback to be called whenever this waitable is executed.
/**
* \param[in] on_execute_callback The new callback
*/
RCLCPP_PUBLIC
void
set_execute_callback(std::function<void(void)> on_execute_callback);
/// Remove a guard condition from being waited on.
/**
* \param[in] weak_guard_condition The guard condition to remove.
*/
RCLCPP_PUBLIC
void
remove_guard_condition(const rclcpp::GuardCondition::WeakPtr & weak_guard_condition);
/// Get the number of ready guard_conditions
/**
* \return The number of guard_conditions associated with the Waitable.
*/
RCLCPP_PUBLIC
size_t
get_number_of_ready_guard_conditions() override;
/// Returns the number of used Timers
/**
* Will always return an empty vector.
*/
RCLCPP_PUBLIC
std::vector<std::shared_ptr<rclcpp::TimerBase>>
get_timers() const override;
private:
/// Callback to run when waitable executes
std::function<void(void)> execute_callback_;
/// Mutex to procetect the guard conditions
std::mutex guard_condition_mutex_;
/// Mutex to protect the execute callback
std::mutex execute_mutex_;
std::function<void(size_t)> on_ready_callback_;
/// The collection of guard conditions to be waited on.
std::set<rclcpp::GuardCondition::SharedPtr> notify_guard_conditions_;
/// The indixes were our guard conditions were stored in the
/// rcl waitset
std::vector<size_t> idxs_of_added_guard_condition_;
/// set to true, if we got a pending trigger
bool needs_processing = false;
/// A guard condition needed to generate wakeups
rclcpp::GuardCondition::SharedPtr guard_condition_;
};
} // namespace executors
} // namespace rclcpp
#endif // RCLCPP__EXECUTORS__EXECUTOR_NOTIFY_WAITABLE_HPP_

View File

@@ -47,12 +47,12 @@ public:
*
* \param options common options for all executors
* \param number_of_threads number of threads to have in the thread pool,
* the default 0 will use the number of cpu cores found instead
* the default 0 will use the number of cpu cores found (minimum of 2)
* \param yield_before_execute if true std::this_thread::yield() is called
* \param timeout maximum time to wait
*/
RCLCPP_PUBLIC
MultiThreadedExecutor(
explicit MultiThreadedExecutor(
const rclcpp::ExecutorOptions & options = rclcpp::ExecutorOptions(),
size_t number_of_threads = 0,
bool yield_before_execute = false,

View File

@@ -1,356 +0,0 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__EXECUTORS__STATIC_EXECUTOR_ENTITIES_COLLECTOR_HPP_
#define RCLCPP__EXECUTORS__STATIC_EXECUTOR_ENTITIES_COLLECTOR_HPP_
#include <chrono>
#include <list>
#include <map>
#include <memory>
#include <vector>
#include "rcl/guard_condition.h"
#include "rcl/wait.h"
#include "rclcpp/experimental/executable_list.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/memory_strategy.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/waitable.hpp"
namespace rclcpp
{
namespace executors
{
typedef std::map<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr,
std::owner_less<rclcpp::CallbackGroup::WeakPtr>> WeakCallbackGroupsToNodesMap;
class StaticExecutorEntitiesCollector final
: public rclcpp::Waitable,
public std::enable_shared_from_this<StaticExecutorEntitiesCollector>
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(StaticExecutorEntitiesCollector)
// Constructor
RCLCPP_PUBLIC
StaticExecutorEntitiesCollector() = default;
// Destructor
RCLCPP_PUBLIC
~StaticExecutorEntitiesCollector();
/// Initialize StaticExecutorEntitiesCollector
/**
* \param p_wait_set A reference to the wait set to be used in the executor
* \param memory_strategy Shared pointer to the memory strategy to set.
* \throws std::runtime_error if memory strategy is null
*/
RCLCPP_PUBLIC
void
init(
rcl_wait_set_t * p_wait_set,
rclcpp::memory_strategy::MemoryStrategy::SharedPtr memory_strategy);
/// Finalize StaticExecutorEntitiesCollector to clear resources
RCLCPP_PUBLIC
bool
is_init() {return initialized_;}
RCLCPP_PUBLIC
void
fini();
/// Execute the waitable.
RCLCPP_PUBLIC
void
execute(std::shared_ptr<void> & data) override;
/// Take the data so that it can be consumed with `execute`.
/**
* For `StaticExecutorEntitiesCollector`, this always return `nullptr`.
* \sa rclcpp::Waitable::take_data()
*/
RCLCPP_PUBLIC
std::shared_ptr<void>
take_data() override;
/// Function to add_handles_to_wait_set and wait for work and
/**
* block until the wait set is ready or until the timeout has been exceeded.
* \throws std::runtime_error if wait set couldn't be cleared or filled.
* \throws any rcl errors from rcl_wait, \see rclcpp::exceptions::throw_from_rcl_error()
*/
RCLCPP_PUBLIC
void
refresh_wait_set(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
/**
* \throws std::runtime_error if it couldn't add guard condition to wait set
*/
RCLCPP_PUBLIC
bool
add_to_wait_set(rcl_wait_set_t * wait_set) override;
RCLCPP_PUBLIC
size_t
get_number_of_ready_guard_conditions() override;
/// Add a callback group to an executor.
/**
* \see rclcpp::Executor::add_callback_group
*/
RCLCPP_PUBLIC
bool
add_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr);
/// Add a callback group to an executor.
/**
* \see rclcpp::Executor::add_callback_group
* \return boolean whether the node from the callback group is new
*/
RCLCPP_PUBLIC
bool
add_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
/// Remove a callback group from the executor.
/**
* \see rclcpp::Executor::remove_callback_group
*/
RCLCPP_PUBLIC
bool
remove_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr);
/// Remove a callback group from the executor.
/**
* \see rclcpp::Executor::remove_callback_group_from_map
*/
RCLCPP_PUBLIC
bool
remove_callback_group_from_map(
rclcpp::CallbackGroup::SharedPtr group_ptr,
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
/**
* \see rclcpp::Executor::add_node()
* \throw std::runtime_error if node was already added
*/
RCLCPP_PUBLIC
bool
add_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr);
/**
* \see rclcpp::Executor::remove_node()
* \throw std::runtime_error if no guard condition is associated with node.
*/
RCLCPP_PUBLIC
bool
remove_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr);
RCLCPP_PUBLIC
std::vector<rclcpp::CallbackGroup::WeakPtr>
get_all_callback_groups();
/// Get callback groups that belong to executor.
/**
* \see rclcpp::Executor::get_manually_added_callback_groups()
*/
RCLCPP_PUBLIC
std::vector<rclcpp::CallbackGroup::WeakPtr>
get_manually_added_callback_groups();
/// Get callback groups that belong to executor.
/**
* \see rclcpp::Executor::get_automatically_added_callback_groups_from_nodes()
*/
RCLCPP_PUBLIC
std::vector<rclcpp::CallbackGroup::WeakPtr>
get_automatically_added_callback_groups_from_nodes();
/// Complete all available queued work without blocking.
/**
* This function checks if after the guard condition was triggered
* (or a spurious wakeup happened) we are really ready to execute
* i.e. re-collect entities
*/
RCLCPP_PUBLIC
bool
is_ready(rcl_wait_set_t * wait_set) override;
/// Return number of timers
/**
* \return number of timers
*/
RCLCPP_PUBLIC
size_t
get_number_of_timers() {return exec_list_.number_of_timers;}
/// Return number of subscriptions
/**
* \return number of subscriptions
*/
RCLCPP_PUBLIC
size_t
get_number_of_subscriptions() {return exec_list_.number_of_subscriptions;}
/// Return number of services
/**
* \return number of services
*/
RCLCPP_PUBLIC
size_t
get_number_of_services() {return exec_list_.number_of_services;}
/// Return number of clients
/**
* \return number of clients
*/
RCLCPP_PUBLIC
size_t
get_number_of_clients() {return exec_list_.number_of_clients;}
/// Return number of waitables
/**
* \return number of waitables
*/
RCLCPP_PUBLIC
size_t
get_number_of_waitables() {return exec_list_.number_of_waitables;}
/** Return a SubscritionBase Sharedptr by index.
* \param[in] i The index of the SubscritionBase
* \return a SubscritionBase shared pointer
* \throws std::out_of_range if the argument is higher than the size of the structrue.
*/
RCLCPP_PUBLIC
rclcpp::SubscriptionBase::SharedPtr
get_subscription(size_t i) {return exec_list_.subscription[i];}
/** Return a TimerBase Sharedptr by index.
* \param[in] i The index of the TimerBase
* \return a TimerBase shared pointer
* \throws std::out_of_range if the argument is higher than the size.
*/
RCLCPP_PUBLIC
rclcpp::TimerBase::SharedPtr
get_timer(size_t i) {return exec_list_.timer[i];}
/** Return a ServiceBase Sharedptr by index.
* \param[in] i The index of the ServiceBase
* \return a ServiceBase shared pointer
* \throws std::out_of_range if the argument is higher than the size.
*/
RCLCPP_PUBLIC
rclcpp::ServiceBase::SharedPtr
get_service(size_t i) {return exec_list_.service[i];}
/** Return a ClientBase Sharedptr by index
* \param[in] i The index of the ClientBase
* \return a ClientBase shared pointer
* \throws std::out_of_range if the argument is higher than the size.
*/
RCLCPP_PUBLIC
rclcpp::ClientBase::SharedPtr
get_client(size_t i) {return exec_list_.client[i];}
/** Return a Waitable Sharedptr by index
* \param[in] i The index of the Waitable
* \return a Waitable shared pointer
* \throws std::out_of_range if the argument is higher than the size.
*/
RCLCPP_PUBLIC
rclcpp::Waitable::SharedPtr
get_waitable(size_t i) {return exec_list_.waitable[i];}
private:
/// Function to reallocate space for entities in the wait set.
/**
* \throws std::runtime_error if wait set couldn't be cleared or resized.
*/
void
prepare_wait_set();
void
fill_executable_list();
void
fill_memory_strategy();
/// Return true if the node belongs to the collector
/**
* \param[in] group_ptr a node base interface shared pointer
* \return boolean whether a node belongs the collector
*/
bool
has_node(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) const;
/// Add all callback groups that can be automatically added by any executor
/// and is not already associated with an executor from nodes
/// that are associated with executor
/**
* \see rclcpp::Executor::add_callback_groups_from_nodes_associated_to_executor()
*/
void
add_callback_groups_from_nodes_associated_to_executor();
void
fill_executable_list_from_map(const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
/// Memory strategy: an interface for handling user-defined memory allocation strategies.
rclcpp::memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;
// maps callback groups to nodes.
WeakCallbackGroupsToNodesMap weak_groups_associated_with_executor_to_nodes_;
// maps callback groups to nodes.
WeakCallbackGroupsToNodesMap weak_groups_to_nodes_associated_with_executor_;
typedef std::map<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr,
const rcl_guard_condition_t *,
std::owner_less<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>>
WeakNodesToGuardConditionsMap;
WeakNodesToGuardConditionsMap weak_nodes_to_guard_conditions_;
/// List of weak nodes registered in the static executor
std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> weak_nodes_;
// Mutex to protect vector of new nodes.
std::mutex new_nodes_mutex_;
std::vector<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> new_nodes_;
/// Wait set for managing entities that the rmw layer waits on.
rcl_wait_set_t * p_wait_set_ = nullptr;
/// Executable list: timers, subscribers, clients, services and waitables
rclcpp::experimental::ExecutableList exec_list_;
/// Bool to check if the entities collector has been initialized
bool initialized_ = false;
};
} // namespace executors
} // namespace rclcpp
#endif // RCLCPP__EXECUTORS__STATIC_EXECUTOR_ENTITIES_COLLECTOR_HPP_

View File

@@ -1,222 +0,0 @@
// Copyright 2019 Nobleo Technology
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__EXECUTORS__STATIC_SINGLE_THREADED_EXECUTOR_HPP_
#define RCLCPP__EXECUTORS__STATIC_SINGLE_THREADED_EXECUTOR_HPP_
#include <chrono>
#include <cassert>
#include <cstdlib>
#include <memory>
#include <vector>
#include <string>
#include "rmw/rmw.h"
#include "rclcpp/executor.hpp"
#include "rclcpp/executors/static_executor_entities_collector.hpp"
#include "rclcpp/experimental/executable_list.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/memory_strategies.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/rate.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace executors
{
/// Static executor implementation
/**
* This executor is a static version of the original single threaded executor.
* It's static because it doesn't reconstruct the executable list for every iteration.
* All nodes, callbackgroups, timers, subscriptions etc. are created before
* spin() is called, and modified only when an entity is added/removed to/from a node.
*
* To run this executor instead of SingleThreadedExecutor replace:
* rclcpp::executors::SingleThreadedExecutor exec;
* by
* rclcpp::executors::StaticSingleThreadedExecutor exec;
* in your source code and spin node(s) in the following way:
* exec.add_node(node);
* exec.spin();
* exec.remove_node(node);
*/
class StaticSingleThreadedExecutor : public rclcpp::Executor
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(StaticSingleThreadedExecutor)
/// Default constructor. See the default constructor for Executor.
RCLCPP_PUBLIC
explicit StaticSingleThreadedExecutor(
const rclcpp::ExecutorOptions & options = rclcpp::ExecutorOptions());
/// Default destrcutor.
RCLCPP_PUBLIC
virtual ~StaticSingleThreadedExecutor();
/// Static executor implementation of spin.
/**
* This function will block until work comes in, execute it, and keep blocking.
* It will only be interrupted by a CTRL-C (managed by the global signal handler).
* \throws std::runtime_error when spin() called while already spinning
*/
RCLCPP_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
*/
RCLCPP_PUBLIC
void
add_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
bool notify = true) override;
/// Remove callback group from the executor
/**
* \sa rclcpp::Executor::remove_callback_group
*/
RCLCPP_PUBLIC
void
remove_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr,
bool notify = true) override;
/// Add a node to the executor.
/**
* \sa rclcpp::Executor::add_node
*/
RCLCPP_PUBLIC
void
add_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
bool notify = true) override;
/// Convenience function which takes Node and forwards NodeBaseInterface.
/**
* \sa rclcpp::StaticSingleThreadedExecutor::add_node
*/
RCLCPP_PUBLIC
void
add_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true) override;
/// Remove a node from the executor.
/**
* \sa rclcpp::Executor::remove_node
*/
RCLCPP_PUBLIC
void
remove_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
bool notify = true) override;
/// Convenience function which takes Node and forwards NodeBaseInterface.
/**
* \sa rclcpp::Executor::remove_node
*/
RCLCPP_PUBLIC
void
remove_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true) override;
RCLCPP_PUBLIC
std::vector<rclcpp::CallbackGroup::WeakPtr>
get_all_callback_groups() override;
/// Get callback groups that belong to executor.
/**
* \sa rclcpp::Executor::get_manually_added_callback_groups()
*/
RCLCPP_PUBLIC
std::vector<rclcpp::CallbackGroup::WeakPtr>
get_manually_added_callback_groups() override;
/// Get callback groups that belong to executor.
/**
* \sa rclcpp::Executor::get_automatically_added_callback_groups_from_nodes()
*/
RCLCPP_PUBLIC
std::vector<rclcpp::CallbackGroup::WeakPtr>
get_automatically_added_callback_groups_from_nodes() override;
protected:
/**
* @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.
*/
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;
private:
RCLCPP_DISABLE_COPY(StaticSingleThreadedExecutor)
StaticExecutorEntitiesCollector::SharedPtr entities_collector_;
};
} // namespace executors
} // namespace rclcpp
#endif // RCLCPP__EXECUTORS__STATIC_SINGLE_THREADED_EXECUTOR_HPP_

View File

@@ -15,6 +15,8 @@
#ifndef RCLCPP__EXPERIMENTAL__BUFFERS__BUFFER_IMPLEMENTATION_BASE_HPP_
#define RCLCPP__EXPERIMENTAL__BUFFERS__BUFFER_IMPLEMENTATION_BASE_HPP_
#include <vector>
namespace rclcpp
{
namespace experimental
@@ -31,8 +33,11 @@ public:
virtual BufferT dequeue() = 0;
virtual void enqueue(BufferT request) = 0;
virtual std::vector<BufferT> get_all_data() = 0;
virtual void clear() = 0;
virtual bool has_data() const = 0;
virtual size_t available_capacity() const = 0;
};
} // namespace buffers

View File

@@ -16,13 +16,16 @@
#define RCLCPP__EXPERIMENTAL__BUFFERS__INTRA_PROCESS_BUFFER_HPP_
#include <memory>
#include <stdexcept>
#include <type_traits>
#include <utility>
#include <vector>
#include "rclcpp/allocator/allocator_common.hpp"
#include "rclcpp/allocator/allocator_deleter.hpp"
#include "rclcpp/experimental/buffers/buffer_implementation_base.hpp"
#include "rclcpp/macros.hpp"
#include "tracetools/tracetools.h"
namespace rclcpp
{
@@ -42,6 +45,7 @@ public:
virtual bool has_data() const = 0;
virtual bool use_take_shared_method() const = 0;
virtual size_t available_capacity() const = 0;
};
template<
@@ -63,6 +67,9 @@ public:
virtual MessageSharedPtr consume_shared() = 0;
virtual MessageUniquePtr consume_unique() = 0;
virtual std::vector<MessageSharedPtr> get_all_data_shared() = 0;
virtual std::vector<MessageUniquePtr> get_all_data_unique() = 0;
};
template<
@@ -93,6 +100,10 @@ public:
buffer_ = std::move(buffer_impl);
TRACETOOLS_TRACEPOINT(
rclcpp_buffer_to_ipb,
static_cast<const void *>(buffer_.get()),
static_cast<const void *>(this));
if (!allocator) {
message_allocator_ = std::make_shared<MessageAlloc>();
} else {
@@ -122,6 +133,16 @@ public:
return consume_unique_impl<BufferT>();
}
std::vector<MessageSharedPtr> get_all_data_shared() override
{
return get_all_data_shared_impl();
}
std::vector<MessageUniquePtr> get_all_data_unique() override
{
return get_all_data_unique_impl();
}
bool has_data() const override
{
return buffer_->has_data();
@@ -137,6 +158,11 @@ public:
return std::is_same<BufferT, MessageSharedPtr>::value;
}
size_t available_capacity() const override
{
return buffer_->available_capacity();
}
private:
std::unique_ptr<BufferImplementationBase<BufferT>> buffer_;
@@ -231,6 +257,71 @@ private:
{
return buffer_->dequeue();
}
// MessageSharedPtr to MessageSharedPtr
template<typename T = BufferT>
typename std::enable_if<
std::is_same<T, MessageSharedPtr>::value,
std::vector<MessageSharedPtr>
>::type
get_all_data_shared_impl()
{
return buffer_->get_all_data();
}
// MessageUniquePtr to MessageSharedPtr
template<typename T = BufferT>
typename std::enable_if<
std::is_same<T, MessageUniquePtr>::value,
std::vector<MessageSharedPtr>
>::type
get_all_data_shared_impl()
{
std::vector<MessageSharedPtr> result;
auto uni_ptr_vec = buffer_->get_all_data();
result.reserve(uni_ptr_vec.size());
for (MessageUniquePtr & uni_ptr : uni_ptr_vec) {
result.emplace_back(std::move(uni_ptr));
}
return result;
}
// MessageSharedPtr to MessageUniquePtr
template<typename T = BufferT>
typename std::enable_if<
std::is_same<T, MessageSharedPtr>::value,
std::vector<MessageUniquePtr>
>::type
get_all_data_unique_impl()
{
std::vector<MessageUniquePtr> result;
auto shared_ptr_vec = buffer_->get_all_data();
result.reserve(shared_ptr_vec.size());
for (MessageSharedPtr shared_msg : shared_ptr_vec) {
MessageUniquePtr unique_msg;
MessageDeleter * deleter = std::get_deleter<MessageDeleter, const MessageT>(shared_msg);
auto ptr = MessageAllocTraits::allocate(*message_allocator_.get(), 1);
MessageAllocTraits::construct(*message_allocator_.get(), ptr, *shared_msg);
if (deleter) {
unique_msg = MessageUniquePtr(ptr, *deleter);
} else {
unique_msg = MessageUniquePtr(ptr);
}
result.push_back(std::move(unique_msg));
}
return result;
}
// MessageUniquePtr to MessageUniquePtr
template<typename T = BufferT>
typename std::enable_if<
std::is_same<T, MessageUniquePtr>::value,
std::vector<MessageUniquePtr>
>::type
get_all_data_unique_impl()
{
return buffer_->get_all_data();
}
};
} // namespace buffers

View File

@@ -15,9 +15,6 @@
#ifndef RCLCPP__EXPERIMENTAL__BUFFERS__RING_BUFFER_IMPLEMENTATION_HPP_
#define RCLCPP__EXPERIMENTAL__BUFFERS__RING_BUFFER_IMPLEMENTATION_HPP_
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <mutex>
#include <stdexcept>
@@ -29,6 +26,7 @@
#include "rclcpp/logging.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
#include "tracetools/tracetools.h"
namespace rclcpp
{
@@ -55,6 +53,10 @@ public:
if (capacity == 0) {
throw std::invalid_argument("capacity must be a positive, non-zero value");
}
TRACETOOLS_TRACEPOINT(
rclcpp_construct_ring_buffer,
static_cast<const void *>(this),
capacity_);
}
virtual ~RingBufferImplementation() {}
@@ -65,12 +67,18 @@ public:
*
* \param request the element to be stored in the ring buffer
*/
void enqueue(BufferT request)
void enqueue(BufferT request) override
{
std::lock_guard<std::mutex> lock(mutex_);
write_index_ = next_(write_index_);
ring_buffer_[write_index_] = std::move(request);
TRACETOOLS_TRACEPOINT(
rclcpp_ring_buffer_enqueue,
static_cast<const void *>(this),
write_index_,
size_ + 1,
is_full_());
if (is_full_()) {
read_index_ = next_(read_index_);
@@ -85,16 +93,20 @@ public:
*
* \return the element that is being removed from the ring buffer
*/
BufferT dequeue()
BufferT dequeue() override
{
std::lock_guard<std::mutex> lock(mutex_);
if (!has_data_()) {
RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Calling dequeue on empty intra-process buffer");
throw std::runtime_error("Calling dequeue on empty intra-process buffer");
return BufferT();
}
auto request = std::move(ring_buffer_[read_index_]);
TRACETOOLS_TRACEPOINT(
rclcpp_ring_buffer_dequeue,
static_cast<const void *>(this),
read_index_,
size_ - 1);
read_index_ = next_(read_index_);
size_--;
@@ -102,6 +114,17 @@ public:
return request;
}
/// Get all the elements from the ring buffer
/**
* This member function is thread-safe.
*
* \return a vector containing all the elements from the ring buffer
*/
std::vector<BufferT> get_all_data() override
{
return get_all_data_impl();
}
/// Get the next index value for the ring buffer
/**
* This member function is thread-safe.
@@ -121,7 +144,7 @@ public:
*
* \return `true` if there is data and `false` otherwise
*/
inline bool has_data() const
inline bool has_data() const override
{
std::lock_guard<std::mutex> lock(mutex_);
return has_data_();
@@ -140,7 +163,24 @@ public:
return is_full_();
}
void clear() {}
/// Get the remaining capacity to store messages
/**
* This member function is thread-safe.
*
* \return the number of free capacity for new messages
*/
size_t available_capacity() const override
{
std::lock_guard<std::mutex> lock(mutex_);
return available_capacity_();
}
void clear() override
{
TRACETOOLS_TRACEPOINT(rclcpp_ring_buffer_clear, static_cast<const void *>(this));
std::lock_guard<std::mutex> lock(mutex_);
clear_();
}
private:
/// Get the next index value for the ring buffer
@@ -178,7 +218,95 @@ private:
return size_ == capacity_;
}
size_t capacity_;
/// Get the remaining capacity to store messages
/**
* This member function is not thread-safe.
*
* \return the number of free capacity for new messages
*/
inline size_t available_capacity_() const
{
return capacity_ - size_;
}
inline void clear_()
{
ring_buffer_.clear();
size_ = 0;
read_index_ = 0;
write_index_ = capacity_ - 1;
}
/// Traits for checking if a type is std::unique_ptr
template<typename ...>
struct is_std_unique_ptr final : std::false_type {};
template<class T, typename ... Args>
struct is_std_unique_ptr<std::unique_ptr<T, Args...>> final : std::true_type
{
typedef T Ptr_type;
};
/// Get all the elements from the ring buffer
/**
* This member function is thread-safe.
* Two versions for the implementation of the function.
* One for buffer containing unique_ptr and the other for other types
*
* \return a vector containing all the elements from the ring buffer
*/
template<typename T = BufferT, std::enable_if_t<is_std_unique_ptr<T>::value &&
std::is_copy_constructible<
typename is_std_unique_ptr<T>::Ptr_type
>::value,
void> * = nullptr>
std::vector<BufferT> get_all_data_impl()
{
std::lock_guard<std::mutex> lock(mutex_);
std::vector<BufferT> result_vtr;
result_vtr.reserve(size_);
for (size_t id = 0; id < size_; ++id) {
const auto & elem(ring_buffer_[(read_index_ + id) % capacity_]);
if (elem != nullptr) {
result_vtr.emplace_back(new typename is_std_unique_ptr<T>::Ptr_type(
*elem));
} else {
result_vtr.emplace_back(nullptr);
}
}
return result_vtr;
}
template<typename T = BufferT, std::enable_if_t<
std::is_copy_constructible<T>::value, void> * = nullptr>
std::vector<BufferT> get_all_data_impl()
{
std::lock_guard<std::mutex> lock(mutex_);
std::vector<BufferT> result_vtr;
result_vtr.reserve(size_);
for (size_t id = 0; id < size_; ++id) {
result_vtr.emplace_back(ring_buffer_[(read_index_ + id) % capacity_]);
}
return result_vtr;
}
template<typename T = BufferT, std::enable_if_t<!is_std_unique_ptr<T>::value &&
!std::is_copy_constructible<T>::value, void> * = nullptr>
std::vector<BufferT> get_all_data_impl()
{
throw std::logic_error("Underlined type results in invalid get_all_data_impl()");
return {};
}
template<typename T = BufferT, std::enable_if_t<is_std_unique_ptr<T>::value &&
!std::is_copy_constructible<typename is_std_unique_ptr<T>::Ptr_type>::value,
void> * = nullptr>
std::vector<BufferT> get_all_data_impl()
{
throw std::logic_error("Underlined type in unique_ptr results in invalid get_all_data_impl()");
return {};
}
const size_t capacity_;
std::vector<BufferT> ring_buffer_;

View File

@@ -16,11 +16,9 @@
#define RCLCPP__EXPERIMENTAL__CREATE_INTRA_PROCESS_BUFFER_HPP_
#include <memory>
#include <type_traits>
#include <stdexcept>
#include <utility>
#include "rcl/subscription.h"
#include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
#include "rclcpp/experimental/buffers/ring_buffer_implementation.hpp"
#include "rclcpp/intra_process_buffer_type.hpp"
@@ -84,10 +82,9 @@ create_intra_process_buffer(
break;
}
default:
case IntraProcessBufferType::CallbackDefault:
{
throw std::runtime_error("Unrecognized IntraProcessBufferType value");
break;
throw std::runtime_error("IntraProcessBufferType::CallbackDefault is not allowed");
}
}

View File

@@ -15,7 +15,6 @@
#ifndef RCLCPP__EXPERIMENTAL__EXECUTABLE_LIST_HPP_
#define RCLCPP__EXPERIMENTAL__EXECUTABLE_LIST_HPP_
#include <memory>
#include <vector>
#include "rclcpp/client.hpp"

View File

@@ -0,0 +1,211 @@
// Copyright 2023 iRobot 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__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_HPP_
#define RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_HPP_
#include <atomic>
#include <chrono>
#include <memory>
#include <vector>
#include "rclcpp/executor.hpp"
#include "rclcpp/executors/executor_entities_collection.hpp"
#include "rclcpp/executors/executor_entities_collector.hpp"
#include "rclcpp/experimental/executors/events_executor/events_executor_event_types.hpp"
#include "rclcpp/experimental/executors/events_executor/events_queue.hpp"
#include "rclcpp/experimental/executors/events_executor/simple_events_queue.hpp"
#include "rclcpp/experimental/timers_manager.hpp"
#include "rclcpp/node.hpp"
namespace rclcpp
{
namespace experimental
{
namespace executors
{
/// Events executor implementation
/**
* This executor uses an events queue and a timers manager to execute entities from its
* associated nodes and callback groups.
* ROS 2 entities allow to set callback functions that are invoked when the entity is triggered
* or has work to do. The events-executor sets these callbacks such that they push an
* event into its queue.
*
* This executor tries to reduce as much as possible the amount of maintenance operations.
* This allows to use customized `EventsQueue` classes to achieve different goals such
* as very low CPU usage, bounded memory requirement, determinism, etc.
*
* The executor uses a weak ownership model and it locks entities only while executing
* their related events.
*
* To run this executor:
* rclcpp::experimental::executors::EventsExecutor executor;
* executor.add_node(node);
* executor.spin();
* executor.remove_node(node);
*/
class EventsExecutor : public rclcpp::Executor
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(EventsExecutor)
/// Default constructor. See the default constructor for Executor.
/**
* \param[in] options Options used to configure the executor.
* \param[in] events_queue The queue used to store events.
* \param[in] execute_timers_separate_thread If true, timers are executed in a separate
* thread. If false, timers are executed in the same thread as all other entities.
*/
RCLCPP_PUBLIC
EventsExecutor(
const rclcpp::ExecutorOptions & options = rclcpp::ExecutorOptions(),
rclcpp::experimental::executors::EventsQueue::UniquePtr events_queue = std::make_unique<
rclcpp::experimental::executors::SimpleEventsQueue>(),
bool execute_timers_separate_thread = false);
/// Default destructor.
RCLCPP_PUBLIC
virtual ~EventsExecutor();
/// Events executor implementation of spin.
/**
* This function will block until work comes in, execute it, and keep blocking.
* It will only be interrupted by a CTRL-C (managed by the global signal handler).
* \throws std::runtime_error when spin() called while already spinning
*/
RCLCPP_PUBLIC
void
spin() override;
/// Events executor implementation of spin some
/**
* This non-blocking function will execute the timers and events
* that were ready when this API was called, until timeout or no
* more work available. New ready-timers/events arrived 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;
/// Events executor implementation of spin all
/**
* This non-blocking function will execute timers and events
* until timeout or no more work available. If new ready-timers/events
* arrive 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;
protected:
/// Internal implementation of spin_once
RCLCPP_PUBLIC
void
spin_once_impl(std::chrono::nanoseconds timeout) override;
/// Internal implementation of spin_some
RCLCPP_PUBLIC
void
spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive);
/// Collect entities from callback groups and refresh the current collection with them
RCLCPP_PUBLIC
void
handle_updated_entities(bool notify) override;
private:
RCLCPP_DISABLE_COPY(EventsExecutor)
/// Execute a provided executor event if its associated entities are available
void
execute_event(const ExecutorEvent & event);
/// Rebuilds the executor's notify waitable, as we can't use the one built in the base class
void
setup_notify_waitable();
/// Refresh the current collection using the provided new_collection
void
refresh_current_collection(const rclcpp::executors::ExecutorEntitiesCollection & new_collection);
/// Create a listener callback function for the provided entity
std::function<void(size_t)>
create_entity_callback(void * entity_key, ExecutorEventType type);
/// Create a listener callback function for the provided waitable entity
std::function<void(size_t, int)>
create_waitable_callback(const rclcpp::Waitable * waitable_id);
/// Utility to add the notify waitable to an entities collection
void
add_notify_waitable_to_collection(
rclcpp::executors::ExecutorEntitiesCollection::WaitableCollection & collection);
/// Searches for the provided entity_id in the collection and returns the entity if valid
template<typename CollectionType>
typename CollectionType::EntitySharedPtr
retrieve_entity(typename CollectionType::Key entity_id, CollectionType & collection)
{
// Note: we lock the mutex because we assume that you are trying to get an element from the
// current collection... If there will be a use-case to retrieve elements also from other
// collections, we can move the mutex back to the calling codes.
std::lock_guard<std::mutex> guard(mutex_);
// Check if the entity_id is in the collection
auto it = collection.find(entity_id);
if (it == collection.end()) {
return nullptr;
}
// Check if the entity associated with the entity_id is valid
// and remove it from the collection if it isn't
auto entity = it->second.entity.lock();
if (!entity) {
collection.erase(it);
}
// Return the retrieved entity (this can be a nullptr if the entity was not valid)
return entity;
}
/// Queue where entities can push events
rclcpp::experimental::executors::EventsQueue::UniquePtr events_queue_;
/// Timers manager used to track and/or execute associated timers
std::shared_ptr<rclcpp::experimental::TimersManager> timers_manager_;
};
} // namespace executors
} // namespace experimental
} // namespace rclcpp
#endif // RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_HPP_

View File

@@ -0,0 +1,49 @@
// Copyright 2023 iRobot 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__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_EVENT_TYPES_HPP_
#define RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_EVENT_TYPES_HPP_
#include <memory>
namespace rclcpp
{
namespace experimental
{
namespace executors
{
enum ExecutorEventType
{
CLIENT_EVENT,
SUBSCRIPTION_EVENT,
SERVICE_EVENT,
TIMER_EVENT,
WAITABLE_EVENT
};
struct ExecutorEvent
{
const void * entity_key;
std::shared_ptr<void> data;
int waitable_data;
ExecutorEventType type;
size_t num_events;
};
} // namespace executors
} // namespace experimental
} // namespace rclcpp
#endif // RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_EVENT_TYPES_HPP_

View File

@@ -0,0 +1,100 @@
// Copyright 2023 iRobot 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__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_QUEUE_HPP_
#define RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_QUEUE_HPP_
#include <queue>
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/experimental/executors/events_executor/events_executor_event_types.hpp"
namespace rclcpp
{
namespace experimental
{
namespace executors
{
/**
* @brief This abstract class can be used to implement different types of queues
* where `ExecutorEvent` can be stored.
* The derived classes should choose which underlying container to use and
* the strategy for pushing and popping events.
* For example a queue implementation may be bounded or unbounded and have
* different pruning strategies.
* Implementations may or may not check the validity of events and decide how to handle
* the situation where an event is not valid anymore (e.g. a subscription history cache overruns)
*/
class EventsQueue
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(EventsQueue)
RCLCPP_PUBLIC
EventsQueue() = default;
/**
* @brief Destruct the object.
*/
RCLCPP_PUBLIC
virtual ~EventsQueue() = default;
/**
* @brief push event into the queue
* @param event The event to push into the queue
*/
RCLCPP_PUBLIC
virtual
void
enqueue(const rclcpp::experimental::executors::ExecutorEvent & event) = 0;
/**
* @brief Extracts an event from the queue, eventually waiting until timeout
* if none is available.
* @return true if event has been found, false if timeout
*/
RCLCPP_PUBLIC
virtual
bool
dequeue(
rclcpp::experimental::executors::ExecutorEvent & event,
std::chrono::nanoseconds timeout = std::chrono::nanoseconds::max()) = 0;
/**
* @brief Test whether queue is empty
* @return true if the queue's size is 0, false otherwise.
*/
RCLCPP_PUBLIC
virtual
bool
empty() const = 0;
/**
* @brief Returns the number of elements in the queue.
* @return the number of elements in the queue.
*/
RCLCPP_PUBLIC
virtual
size_t
size() const = 0;
};
} // namespace executors
} // namespace experimental
} // namespace rclcpp
#endif // RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_QUEUE_HPP_

View File

@@ -0,0 +1,134 @@
// Copyright 2023 iRobot 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__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__SIMPLE_EVENTS_QUEUE_HPP_
#define RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__SIMPLE_EVENTS_QUEUE_HPP_
#include <condition_variable>
#include <mutex>
#include <queue>
#include <utility>
#include "rclcpp/experimental/executors/events_executor/events_queue.hpp"
namespace rclcpp
{
namespace experimental
{
namespace executors
{
/**
* @brief This class implements an EventsQueue as a simple wrapper around a std::queue.
* It does not perform any checks about the size of queue, which can grow
* unbounded without being pruned.
* The simplicity of this implementation makes it suitable for optimizing CPU usage.
*/
class SimpleEventsQueue : public EventsQueue
{
public:
RCLCPP_PUBLIC
~SimpleEventsQueue() override = default;
/**
* @brief enqueue event into the queue
* Thread safe
* @param event The event to enqueue into the queue
*/
RCLCPP_PUBLIC
void
enqueue(const rclcpp::experimental::executors::ExecutorEvent & event) override
{
rclcpp::experimental::executors::ExecutorEvent single_event = event;
single_event.num_events = 1;
{
std::unique_lock<std::mutex> lock(mutex_);
for (size_t ev = 0; ev < event.num_events; ev++) {
event_queue_.push(single_event);
}
}
events_queue_cv_.notify_one();
}
/**
* @brief waits for an event until timeout, gets a single event
* Thread safe
* @return true if event, false if timeout
*/
RCLCPP_PUBLIC
bool
dequeue(
rclcpp::experimental::executors::ExecutorEvent & event,
std::chrono::nanoseconds timeout = std::chrono::nanoseconds::max()) override
{
std::unique_lock<std::mutex> lock(mutex_);
// Initialize to true because it's only needed if we have a valid timeout
bool has_data = true;
if (timeout != std::chrono::nanoseconds::max()) {
has_data =
events_queue_cv_.wait_for(lock, timeout, [this]() {return !event_queue_.empty();});
} else {
events_queue_cv_.wait(lock, [this]() {return !event_queue_.empty();});
}
if (has_data) {
event = event_queue_.front();
event_queue_.pop();
return true;
}
return false;
}
/**
* @brief Test whether queue is empty
* Thread safe
* @return true if the queue's size is 0, false otherwise.
*/
RCLCPP_PUBLIC
bool
empty() const override
{
std::unique_lock<std::mutex> lock(mutex_);
return event_queue_.empty();
}
/**
* @brief Returns the number of elements in the queue.
* Thread safe
* @return the number of elements in the queue.
*/
RCLCPP_PUBLIC
size_t
size() const override
{
std::unique_lock<std::mutex> lock(mutex_);
return event_queue_.size();
}
private:
// The underlying queue implementation
std::queue<rclcpp::experimental::executors::ExecutorEvent> event_queue_;
// Mutex to protect read/write access to the queue
mutable std::mutex mutex_;
// Variable used to notify when an event is added to the queue
std::condition_variable events_queue_cv_;
};
} // namespace executors
} // namespace experimental
} // namespace rclcpp
#endif // RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__SIMPLE_EVENTS_QUEUE_HPP_

View File

@@ -20,17 +20,17 @@
#include <shared_mutex>
#include <algorithm>
#include <atomic>
#include <cstdint>
#include <exception>
#include <map>
#include <iterator>
#include <memory>
#include <string>
#include <stdexcept>
#include <unordered_map>
#include <utility>
#include <vector>
#include <typeinfo>
#include "rclcpp/allocator/allocator_deleter.hpp"
#include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
#include "rclcpp/experimental/ros_message_intra_process_buffer.hpp"
#include "rclcpp/experimental/subscription_intra_process.hpp"
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
#include "rclcpp/experimental/subscription_intra_process_buffer.hpp"
@@ -38,6 +38,7 @@
#include "rclcpp/logging.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/publisher_base.hpp"
#include "rclcpp/type_adapter.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
@@ -113,9 +114,41 @@ public:
* \param subscription the SubscriptionIntraProcess to register.
* \return an unsigned 64-bit integer which is the subscription's unique id.
*/
RCLCPP_PUBLIC
template<
typename ROSMessageType,
typename Alloc = std::allocator<ROSMessageType>
>
uint64_t
add_subscription(rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr subscription);
add_subscription(
const rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr & subscription)
{
std::unique_lock<std::shared_timed_mutex> lock(mutex_);
uint64_t sub_id = IntraProcessManager::get_next_unique_id();
subscriptions_[sub_id] = subscription;
// adds the subscription id to all the matchable publishers
for (auto & pair : publishers_) {
auto publisher = pair.second.lock();
if (!publisher) {
continue;
}
if (can_communicate(publisher, subscription)) {
uint64_t pub_id = pair.first;
insert_sub_id_for_pub(sub_id, pub_id, subscription->use_take_shared_method());
if (publisher->is_durability_transient_local() &&
subscription->is_durability_transient_local())
{
do_transient_local_publish<ROSMessageType, Alloc>(
pub_id, sub_id,
subscription->use_take_shared_method());
}
}
}
return sub_id;
}
/// Unregister a subscription using the subscription's unique id.
/**
@@ -132,14 +165,21 @@ public:
* This method stores the publisher intra process object, together with
* the information of its wrapped publisher (i.e. topic name and QoS).
*
* If the publisher's durability is transient local, its buffer pointer should
* be passed and the method will store it as well.
*
* In addition this generates a unique intra process id for the publisher.
*
* \param publisher publisher to be registered with the manager.
* \param buffer publisher's buffer to be stored if its duability is transient local.
* \return an unsigned 64-bit integer which is the publisher's unique id.
*/
RCLCPP_PUBLIC
uint64_t
add_publisher(rclcpp::PublisherBase::SharedPtr publisher);
add_publisher(
const rclcpp::PublisherBase::SharedPtr & publisher,
const rclcpp::experimental::buffers::IntraProcessBufferBase::SharedPtr & buffer =
rclcpp::experimental::buffers::IntraProcessBufferBase::SharedPtr());
/// Unregister a publisher using the publisher's unique id.
/**
@@ -173,11 +213,14 @@ public:
*
* \param intra_process_publisher_id the id of the publisher of this message.
* \param message the message that is being stored.
* \param allocator for allocations when buffering messages.
*/
template<
typename MessageT,
typename Alloc = std::allocator<void>,
typename Deleter = std::default_delete<MessageT>>
typename ROSMessageType,
typename Alloc,
typename Deleter = std::default_delete<MessageT>
>
void
do_intra_process_publish(
uint64_t intra_process_publisher_id,
@@ -203,7 +246,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>(
this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
msg, sub_ids.take_shared_subscriptions);
} else if (!sub_ids.take_ownership_subscriptions.empty() && // NOLINT
sub_ids.take_shared_subscriptions.size() <= 1)
@@ -212,13 +255,13 @@ public:
// So this case is equivalent to all the buffers requiring ownership
// Merge the two vector of ids into a unique one
std::vector<uint64_t> concatenated_vector(sub_ids.take_shared_subscriptions);
std::vector<uint64_t> concatenated_vector(
sub_ids.take_shared_subscriptions.begin(), sub_ids.take_shared_subscriptions.end());
concatenated_vector.insert(
concatenated_vector.end(),
sub_ids.take_ownership_subscriptions.begin(),
sub_ids.take_ownership_subscriptions.end());
this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter>(
this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
std::move(message),
concatenated_vector,
allocator);
@@ -229,17 +272,19 @@ 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, Alloc, Deleter, ROSMessageType>(
shared_msg, sub_ids.take_shared_subscriptions);
this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter>(
this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
std::move(message), sub_ids.take_ownership_subscriptions, allocator);
}
}
template<
typename MessageT,
typename Alloc = std::allocator<void>,
typename Deleter = std::default_delete<MessageT>>
typename ROSMessageType,
typename Alloc,
typename Deleter = std::default_delete<MessageT>
>
std::shared_ptr<const MessageT>
do_intra_process_publish_and_return_shared(
uint64_t intra_process_publisher_id,
@@ -265,7 +310,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, Alloc, Deleter, ROSMessageType>(
shared_msg, sub_ids.take_shared_subscriptions);
}
return shared_msg;
@@ -275,21 +320,48 @@ 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, Alloc, Deleter, ROSMessageType>(
shared_msg,
sub_ids.take_shared_subscriptions);
}
if (!sub_ids.take_ownership_subscriptions.empty()) {
this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter>(
this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
std::move(message),
sub_ids.take_ownership_subscriptions,
allocator);
}
return shared_msg;
}
}
template<
typename MessageT,
typename Alloc,
typename Deleter,
typename ROSMessageType>
void
add_shared_msg_to_buffer(
std::shared_ptr<const MessageT> message,
uint64_t subscription_id)
{
add_shared_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(message, {subscription_id});
}
template<
typename MessageT,
typename Alloc,
typename Deleter,
typename ROSMessageType>
void
add_owned_msg_to_buffer(
std::unique_ptr<MessageT, Deleter> message,
uint64_t subscription_id,
typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
{
add_owned_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
std::move(message), {subscription_id}, allocator);
}
/// Return true if the given rmw_gid_t matches any stored Publishers.
RCLCPP_PUBLIC
bool
@@ -304,6 +376,11 @@ public:
rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr
get_subscription_intra_process(uint64_t intra_process_subscription_id);
/// Return the lowest available capacity for all subscription buffers for a publisher id.
RCLCPP_PUBLIC
size_t
lowest_available_capacity(const uint64_t intra_process_publisher_id) const;
private:
struct SplittedSubscriptions
{
@@ -311,15 +388,61 @@ private:
std::vector<uint64_t> take_ownership_subscriptions;
};
/// Hash function for rmw_gid_t to enable use in unordered_map
struct rmw_gid_hash
{
std::size_t operator()(const rmw_gid_t & gid) const noexcept
{
// Using the FNV-1a hash algorithm on the gid data
constexpr std::size_t FNV_prime = 1099511628211u;
std::size_t result = 14695981039346656037u;
for (std::size_t i = 0; i < RMW_GID_STORAGE_SIZE; ++i) {
result ^= gid.data[i];
result *= FNV_prime;
}
return result;
}
};
/// Equality comparison for rmw_gid_t to enable use in unordered_map
struct rmw_gid_equal
{
bool operator()(const rmw_gid_t & lhs, const rmw_gid_t & rhs) const noexcept
{
// Compare the data bytes only.
// implementation_identifier pointer comparison is not used here because
// intra-process communication is always within the same process and RMW,
// and pointer comparison is fragile across dynamically loaded components.
return std::equal(
std::begin(lhs.data),
std::end(lhs.data),
std::begin(rhs.data));
}
};
using SubscriptionMap =
std::unordered_map<uint64_t, rclcpp::experimental::SubscriptionIntraProcessBase::WeakPtr>;
using PublisherMap =
std::unordered_map<uint64_t, rclcpp::PublisherBase::WeakPtr>;
using PublisherBufferMap =
std::unordered_map<uint64_t, rclcpp::experimental::buffers::IntraProcessBufferBase::WeakPtr>;
using PublisherToSubscriptionIdsMap =
std::unordered_map<uint64_t, SplittedSubscriptions>;
/// Structure to store publisher information in GID lookup map
struct PublisherInfo
{
uint64_t pub_id;
rclcpp::PublisherBase::WeakPtr publisher;
};
using GidToPublisherInfoMap =
std::unordered_map<rmw_gid_t, PublisherInfo, rmw_gid_hash, rmw_gid_equal>;
RCLCPP_PUBLIC
static
uint64_t
@@ -332,47 +455,137 @@ private:
RCLCPP_PUBLIC
bool
can_communicate(
rclcpp::PublisherBase::SharedPtr pub,
rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr sub) const;
const rclcpp::PublisherBase::SharedPtr & pub,
const rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr & sub) const;
template<
typename MessageT,
typename Alloc,
typename Deleter>
void
add_shared_msg_to_buffers(
std::shared_ptr<const MessageT> message,
std::vector<uint64_t> subscription_ids)
typename ROSMessageType,
typename Alloc = std::allocator<ROSMessageType>
>
void do_transient_local_publish(
const uint64_t pub_id, const uint64_t sub_id,
const bool use_take_shared_method)
{
for (auto id : subscription_ids) {
auto subscription_it = subscriptions_.find(id);
if (subscription_it == subscriptions_.end()) {
throw std::runtime_error("subscription has unexpectedly gone out of scope");
}
auto subscription_base = subscription_it->second.lock();
if (subscription_base) {
auto subscription = std::dynamic_pointer_cast<
rclcpp::experimental::SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>
>(subscription_base);
if (nullptr == subscription) {
throw std::runtime_error(
"failed to dynamic cast SubscriptionIntraProcessBase to "
"SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>, which "
"can happen when the publisher and subscription use different "
"allocator types, which is not supported");
}
using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, Alloc>;
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
subscription->provide_intra_process_message(message);
} else {
subscriptions_.erase(id);
auto publisher_buffer = publisher_buffers_[pub_id].lock();
if (!publisher_buffer) {
throw std::runtime_error("publisher buffer has unexpectedly gone out of scope");
}
auto buffer = std::dynamic_pointer_cast<
rclcpp::experimental::buffers::IntraProcessBuffer<
ROSMessageType,
ROSMessageTypeAllocator,
ROSMessageTypeDeleter
>
>(publisher_buffer);
if (!buffer) {
throw std::runtime_error(
"failed to dynamic cast publisher's IntraProcessBufferBase to "
"IntraProcessBuffer<ROSMessageType,ROSMessageTypeAllocator,"
"ROSMessageTypeDeleter> which can happen when the publisher and "
"subscription use different allocator types, which is not supported");
}
if (use_take_shared_method) {
auto data_vec = buffer->get_all_data_shared();
for (auto shared_data : data_vec) {
this->template add_shared_msg_to_buffer<
ROSMessageType, ROSMessageTypeAllocator, ROSMessageTypeDeleter, ROSMessageType>(
shared_data, sub_id);
}
} else {
auto data_vec = buffer->get_all_data_unique();
for (auto & owned_data : data_vec) {
auto allocator = ROSMessageTypeAllocator();
this->template add_owned_msg_to_buffer<
ROSMessageType, ROSMessageTypeAllocator, ROSMessageTypeDeleter, ROSMessageType>(
std::move(owned_data), sub_id, allocator);
}
}
}
template<
typename MessageT,
typename Alloc = std::allocator<void>,
typename Deleter = std::default_delete<MessageT>>
typename Alloc,
typename Deleter,
typename ROSMessageType>
void
add_shared_msg_to_buffers(
std::shared_ptr<const MessageT> message,
std::vector<uint64_t> subscription_ids)
{
using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, Alloc>;
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
using PublishedType = typename rclcpp::TypeAdapter<MessageT>::custom_type;
using PublishedTypeAllocatorTraits = allocator::AllocRebind<PublishedType, Alloc>;
using PublishedTypeAllocator = typename PublishedTypeAllocatorTraits::allocator_type;
using PublishedTypeDeleter = allocator::Deleter<PublishedTypeAllocator, PublishedType>;
for (auto id : subscription_ids) {
auto subscription_it = subscriptions_.find(id);
if (subscription_it == subscriptions_.end()) {
throw std::runtime_error("subscription has unexpectedly gone out of scope");
}
auto subscription_base = subscription_it->second.lock();
if (subscription_base == nullptr) {
subscriptions_.erase(id);
continue;
}
auto subscription = std::dynamic_pointer_cast<
rclcpp::experimental::SubscriptionIntraProcessBuffer<PublishedType,
PublishedTypeAllocator, PublishedTypeDeleter, ROSMessageType>
>(subscription_base);
if (subscription != nullptr) {
subscription->provide_intra_process_data(message);
continue;
}
auto ros_message_subscription = std::dynamic_pointer_cast<
rclcpp::experimental::SubscriptionROSMsgIntraProcessBuffer<ROSMessageType,
ROSMessageTypeAllocator, ROSMessageTypeDeleter>
>(subscription_base);
if (nullptr == ros_message_subscription) {
throw std::runtime_error(
"failed to dynamic cast SubscriptionIntraProcessBase to "
"SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>, or to "
"SubscriptionROSMsgIntraProcessBuffer<ROSMessageType,ROSMessageTypeAllocator,"
"ROSMessageTypeDeleter> which can happen when the publisher and "
"subscription use different allocator types, which is not supported");
}
if constexpr (rclcpp::TypeAdapter<MessageT>::is_specialized::value) {
ROSMessageType ros_msg;
rclcpp::TypeAdapter<MessageT>::convert_to_ros_message(*message, ros_msg);
ros_message_subscription->provide_intra_process_message(
std::make_shared<ROSMessageType>(ros_msg));
} else {
if constexpr (std::is_same<MessageT, ROSMessageType>::value) {
ros_message_subscription->provide_intra_process_message(message);
} else {
if constexpr (std::is_same<typename rclcpp::TypeAdapter<MessageT,
ROSMessageType>::ros_message_type, ROSMessageType>::value)
{
ROSMessageType ros_msg;
rclcpp::TypeAdapter<MessageT, ROSMessageType>::convert_to_ros_message(
*message, ros_msg);
ros_message_subscription->provide_intra_process_message(
std::make_shared<ROSMessageType>(ros_msg));
}
}
}
}
}
template<
typename MessageT,
typename Alloc,
typename Deleter,
typename ROSMessageType>
void
add_owned_msg_to_buffers(
std::unique_ptr<MessageT, Deleter> message,
@@ -382,39 +595,88 @@ private:
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, Alloc>;
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
using PublishedType = typename rclcpp::TypeAdapter<MessageT>::custom_type;
using PublishedTypeAllocatorTraits = allocator::AllocRebind<PublishedType, Alloc>;
using PublishedTypeAllocator = typename PublishedTypeAllocatorTraits::allocator_type;
using PublishedTypeDeleter = allocator::Deleter<PublishedTypeAllocator, PublishedType>;
for (auto it = subscription_ids.begin(); it != subscription_ids.end(); it++) {
auto subscription_it = subscriptions_.find(*it);
if (subscription_it == subscriptions_.end()) {
throw std::runtime_error("subscription has unexpectedly gone out of scope");
}
auto subscription_base = subscription_it->second.lock();
if (subscription_base) {
auto subscription = std::dynamic_pointer_cast<
rclcpp::experimental::SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>
>(subscription_base);
if (nullptr == subscription) {
throw std::runtime_error(
"failed to dynamic cast SubscriptionIntraProcessBase to "
"SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>, which "
"can happen when the publisher and subscription use different "
"allocator types, which is not supported");
}
if (subscription_base == nullptr) {
subscriptions_.erase(subscription_it);
continue;
}
auto subscription = std::dynamic_pointer_cast<
rclcpp::experimental::SubscriptionIntraProcessBuffer<PublishedType,
PublishedTypeAllocator, PublishedTypeDeleter, ROSMessageType>
>(subscription_base);
if (subscription != nullptr) {
if (std::next(it) == subscription_ids.end()) {
// If this is the last subscription, give up ownership
subscription->provide_intra_process_message(std::move(message));
subscription->provide_intra_process_data(std::move(message));
// Last message delivered, break from for loop
break;
} else {
// Copy the message since we have additional subscriptions to serve
MessageUniquePtr copy_message;
Deleter deleter = message.get_deleter();
auto ptr = MessageAllocTraits::allocate(allocator, 1);
MessageAllocTraits::construct(allocator, ptr, *message);
copy_message = MessageUniquePtr(ptr, deleter);
subscription->provide_intra_process_message(std::move(copy_message));
subscription->provide_intra_process_data(MessageUniquePtr(ptr, deleter));
}
continue;
}
auto ros_message_subscription = std::dynamic_pointer_cast<
rclcpp::experimental::SubscriptionROSMsgIntraProcessBuffer<ROSMessageType,
ROSMessageTypeAllocator, ROSMessageTypeDeleter>
>(subscription_base);
if (nullptr == ros_message_subscription) {
throw std::runtime_error(
"failed to dynamic cast SubscriptionIntraProcessBase to "
"SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>, or to "
"SubscriptionROSMsgIntraProcessBuffer<ROSMessageType,ROSMessageTypeAllocator,"
"ROSMessageTypeDeleter> which can happen when the publisher and "
"subscription use different allocator types, which is not supported");
}
if constexpr (rclcpp::TypeAdapter<MessageT, ROSMessageType>::is_specialized::value) {
ROSMessageTypeAllocator ros_message_alloc(allocator);
auto ptr = ROSMessageTypeAllocatorTraits::allocate(ros_message_alloc, 1);
ROSMessageTypeAllocatorTraits::construct(ros_message_alloc, ptr);
ROSMessageTypeDeleter deleter;
allocator::set_allocator_for_deleter(&deleter, &allocator);
rclcpp::TypeAdapter<MessageT, ROSMessageType>::convert_to_ros_message(*message, *ptr);
auto ros_msg = std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, deleter);
ros_message_subscription->provide_intra_process_message(std::move(ros_msg));
} else {
subscriptions_.erase(subscription_it);
if constexpr (std::is_same<MessageT, ROSMessageType>::value) {
if (std::next(it) == subscription_ids.end()) {
// If this is the last subscription, give up ownership
ros_message_subscription->provide_intra_process_message(std::move(message));
// Last message delivered, break from for loop
break;
} else {
// Copy the message since we have additional subscriptions to serve
Deleter deleter = message.get_deleter();
allocator::set_allocator_for_deleter(&deleter, &allocator);
auto ptr = MessageAllocTraits::allocate(allocator, 1);
MessageAllocTraits::construct(allocator, ptr, *message);
ros_message_subscription->provide_intra_process_message(
MessageUniquePtr(ptr, deleter));
}
}
}
}
}
@@ -422,8 +684,11 @@ private:
PublisherToSubscriptionIdsMap pub_to_subs_;
SubscriptionMap subscriptions_;
PublisherMap publishers_;
PublisherBufferMap publisher_buffers_;
mutable std::shared_timed_mutex mutex_;
GidToPublisherInfoMap gid_to_publisher_info_;
};
} // namespace experimental

View File

@@ -0,0 +1,68 @@
// 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__EXPERIMENTAL__ROS_MESSAGE_INTRA_PROCESS_BUFFER_HPP_
#define RCLCPP__EXPERIMENTAL__ROS_MESSAGE_INTRA_PROCESS_BUFFER_HPP_
#include <memory>
#include <string>
#include "rcl/error_handling.h"
#include "rclcpp/any_subscription_callback.hpp"
#include "rclcpp/context.hpp"
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
#include "tracetools/tracetools.h"
namespace rclcpp
{
namespace experimental
{
template<
typename RosMessageT,
typename Alloc = std::allocator<void>,
typename Deleter = std::default_delete<void>
>
class SubscriptionROSMsgIntraProcessBuffer : public SubscriptionIntraProcessBase
{
public:
using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<RosMessageT, Alloc>;
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, RosMessageT>;
using ConstMessageSharedPtr = std::shared_ptr<const RosMessageT>;
using MessageUniquePtr = std::unique_ptr<RosMessageT, ROSMessageTypeDeleter>;
SubscriptionROSMsgIntraProcessBuffer(
rclcpp::Context::SharedPtr context,
const std::string & topic_name,
const rclcpp::QoS & qos_profile)
: SubscriptionIntraProcessBase(context, topic_name, qos_profile)
{}
virtual ~SubscriptionROSMsgIntraProcessBuffer()
{}
virtual void
provide_intra_process_message(ConstMessageSharedPtr message) = 0;
virtual void
provide_intra_process_message(MessageUniquePtr message) = 0;
};
} // namespace experimental
} // namespace rclcpp
#endif // RCLCPP__EXPERIMENTAL__ROS_MESSAGE_INTRA_PROCESS_BUFFER_HPP_

View File

@@ -15,25 +15,22 @@
#ifndef RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_HPP_
#define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_HPP_
#include <rmw/rmw.h>
#include <rmw/types.h>
#include <functional>
#include <map>
#include <memory>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
#include "rcl/error_handling.h"
#include "rcl/types.h"
#include "rclcpp/any_subscription_callback.hpp"
#include "rclcpp/context.hpp"
#include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
#include "rclcpp/experimental/create_intra_process_buffer.hpp"
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
#include "rclcpp/experimental/subscription_intra_process_buffer.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/waitable.hpp"
#include "tracetools/tracetools.h"
namespace rclcpp
@@ -43,47 +40,54 @@ namespace experimental
template<
typename MessageT,
typename Alloc = std::allocator<void>,
typename Deleter = std::default_delete<MessageT>,
typename CallbackMessageT = MessageT>
typename SubscribedType,
typename SubscribedTypeAlloc = std::allocator<SubscribedType>,
typename SubscribedTypeDeleter = std::default_delete<SubscribedType>,
typename ROSMessageType = SubscribedType,
typename Alloc = std::allocator<void>
>
class SubscriptionIntraProcess
: public SubscriptionIntraProcessBuffer<
MessageT,
Alloc,
Deleter
SubscribedType,
SubscribedTypeAlloc,
SubscribedTypeDeleter,
ROSMessageType
>
{
using SubscriptionIntraProcessBufferT = SubscriptionIntraProcessBuffer<
MessageT,
Alloc,
Deleter
SubscribedType,
SubscribedTypeAlloc,
SubscribedTypeDeleter,
ROSMessageType
>;
public:
RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionIntraProcess)
using MessageAllocTraits = typename SubscriptionIntraProcessBufferT::MessageAllocTraits;
using MessageAlloc = typename SubscriptionIntraProcessBufferT::MessageAlloc;
using ConstMessageSharedPtr = typename SubscriptionIntraProcessBufferT::ConstMessageSharedPtr;
using MessageUniquePtr = typename SubscriptionIntraProcessBufferT::MessageUniquePtr;
using MessageAllocTraits =
typename SubscriptionIntraProcessBufferT::SubscribedTypeAllocatorTraits;
using MessageAlloc = typename SubscriptionIntraProcessBufferT::SubscribedTypeAllocator;
using ConstMessageSharedPtr = typename SubscriptionIntraProcessBufferT::ConstDataSharedPtr;
using MessageUniquePtr = typename SubscriptionIntraProcessBufferT::SubscribedTypeUniquePtr;
using BufferUniquePtr = typename SubscriptionIntraProcessBufferT::BufferUniquePtr;
SubscriptionIntraProcess(
AnySubscriptionCallback<CallbackMessageT, Alloc> callback,
AnySubscriptionCallback<MessageT, Alloc> callback,
std::shared_ptr<Alloc> allocator,
rclcpp::Context::SharedPtr context,
const std::string & topic_name,
const rclcpp::QoS & qos_profile,
rclcpp::IntraProcessBufferType buffer_type)
: SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>(
allocator,
: SubscriptionIntraProcessBuffer<SubscribedType, SubscribedTypeAlloc,
SubscribedTypeDeleter, ROSMessageType>(
std::make_shared<SubscribedTypeAlloc>(*allocator),
context,
topic_name,
qos_profile,
buffer_type),
any_callback_(callback)
{
TRACEPOINT(
TRACETOOLS_TRACEPOINT(
rclcpp_subscription_callback_added,
static_cast<const void *>(this),
static_cast<const void *>(&any_callback_));
@@ -97,17 +101,47 @@ public:
virtual ~SubscriptionIntraProcess() = default;
void
add_to_wait_set(rcl_wait_set_t & wait_set) override
{
// This block is necessary when the guard condition wakes the wait set, but
// the intra process waitable was not handled before the wait set is waited
// on again.
// Basically we're keeping the guard condition triggered so long as there is
// data in the buffer.
if (this->buffer_->has_data()) {
// If there is data still to be processed, indicate to the
// executor or waitset by triggering the guard condition.
this->trigger_guard_condition();
}
// Let the parent classes handle the rest of the work:
return SubscriptionIntraProcessBufferT::add_to_wait_set(wait_set);
}
std::shared_ptr<void>
take_data()
take_data() override
{
ConstMessageSharedPtr shared_msg;
MessageUniquePtr unique_msg;
if (any_callback_.use_take_shared_method()) {
shared_msg = this->buffer_->consume_shared();
if (!shared_msg) {
return nullptr;
}
} else {
unique_msg = this->buffer_->consume_unique();
if (!unique_msg) {
return nullptr;
}
}
if (this->buffer_->has_data()) {
// If there is data still to be processed, indicate to the
// executor or waitset by triggering the guard condition.
this->trigger_guard_condition();
}
return std::static_pointer_cast<void>(
std::make_shared<std::pair<ConstMessageSharedPtr, MessageUniquePtr>>(
std::pair<ConstMessageSharedPtr, MessageUniquePtr>(
@@ -115,26 +149,48 @@ public:
);
}
void execute(std::shared_ptr<void> & data)
void execute(const std::shared_ptr<void> & data) override
{
execute_impl<MessageT>(data);
execute_impl<SubscribedType>(data);
}
/// Disable callbacks from being called
/**
* This method will block, until any subscription's callbacks currently being executed are
* finished.
* This method is thread safe, and provides a safe way to atomically disable the callbacks.
*/
void disable_callbacks() override
{
SubscriptionIntraProcessBase::disable_callbacks();
any_callback_.disable();
}
/// Enable the callbacks to be called
/**
* This method is thread safe, and provides a safe way to atomically enable the callbacks
* in a multithreaded environment.
*/
void enable_callbacks() override
{
SubscriptionIntraProcessBase::enable_callbacks();
any_callback_.enable();
}
protected:
template<typename T>
typename std::enable_if<std::is_same<T, rcl_serialized_message_t>::value, void>::type
execute_impl(std::shared_ptr<void> & data)
execute_impl(const std::shared_ptr<void> &)
{
(void)data;
throw std::runtime_error("Subscription intra-process can't handle serialized messages");
}
template<class T>
typename std::enable_if<!std::is_same<T, rcl_serialized_message_t>::value, void>::type
execute_impl(std::shared_ptr<void> & data)
execute_impl(const std::shared_ptr<void> & data)
{
if (!data) {
throw std::runtime_error("'data' is empty");
if (nullptr == data) {
return;
}
rmw_message_info_t msg_info;
@@ -154,7 +210,7 @@ protected:
shared_ptr.reset();
}
AnySubscriptionCallback<CallbackMessageT, Alloc> any_callback_;
AnySubscriptionCallback<MessageT, Alloc> any_callback_;
};
} // namespace experimental

View File

@@ -15,18 +15,18 @@
#ifndef RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BASE_HPP_
#define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BASE_HPP_
#include <rmw/rmw.h>
#include <functional>
#include <algorithm>
#include <memory>
#include <mutex>
#include <string>
#include <utility>
#include <vector>
#include "rcl/error_handling.h"
#include "rcl/wait.h"
#include "rmw/impl/cpp/demangle.hpp"
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/waitable.hpp"
namespace rclcpp
@@ -39,34 +39,72 @@ class SubscriptionIntraProcessBase : public rclcpp::Waitable
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(SubscriptionIntraProcessBase)
enum class EntityType : std::size_t
{
Subscription,
};
RCLCPP_PUBLIC
SubscriptionIntraProcessBase(
rclcpp::Context::SharedPtr context,
const std::string & topic_name,
const rclcpp::QoS & qos_profile)
: topic_name_(topic_name), qos_profile_(qos_profile)
: gc_(context), topic_name_(topic_name), qos_profile_(qos_profile)
{}
RCLCPP_PUBLIC
virtual ~SubscriptionIntraProcessBase() = default;
RCLCPP_PUBLIC
size_t
get_number_of_ready_guard_conditions() {return 1;}
get_number_of_ready_guard_conditions() override {return 1;}
RCLCPP_PUBLIC
void
add_to_wait_set(rcl_wait_set_t & wait_set) override;
RCLCPP_PUBLIC
virtual
size_t
available_capacity() const = 0;
RCLCPP_PUBLIC
bool
add_to_wait_set(rcl_wait_set_t * wait_set);
is_durability_transient_local() const;
virtual bool
is_ready(rcl_wait_set_t * wait_set) = 0;
bool
is_ready(const rcl_wait_set_t & wait_set) override = 0;
std::shared_ptr<void>
take_data() override = 0;
std::shared_ptr<void>
take_data_by_entity_id([[maybe_unused]] size_t id) override
{
return take_data();
}
void
execute(const std::shared_ptr<void> & data) override = 0;
/// Disable callbacks from being called
/**
* This function temporary disable on_new_message_callback to prevent it from being called.
*/
RCLCPP_PUBLIC
virtual
void disable_callbacks();
/// Enable the callbacks to be called
/**
* This function enable the on_new_message_callback if it was previously set.
*/
RCLCPP_PUBLIC
virtual
void enable_callbacks();
virtual
std::shared_ptr<void>
take_data() = 0;
virtual void
execute(std::shared_ptr<void> & data) = 0;
virtual bool
bool
use_take_shared_method() const = 0;
RCLCPP_PUBLIC
@@ -77,14 +115,118 @@ public:
QoS
get_actual_qos() const;
protected:
std::recursive_mutex reentrant_mutex_;
rcl_guard_condition_t gc_;
/// Set a callback to be called when each new message arrives.
/**
* The callback receives a size_t which is the number of messages received
* since the last time this callback was called.
* Normally this is 1, but can be > 1 if messages were received before any
* callback was set.
*
* The callback also receives an int identifier argument.
* This is needed because a Waitable may be composed of several distinct entities,
* such as subscriptions, services, etc.
* The application should provide a generic callback function that will be then
* forwarded by the waitable to all of its entities.
* Before forwarding, a different value for the identifier argument will be
* bound to the function.
* This implies that the provided callback can use the identifier to behave
* differently depending on which entity triggered the waitable to become ready.
*
* Calling it again will clear any previously set callback.
*
* An exception will be thrown if the callback is not callable.
*
* This function is thread-safe.
*
* If you want more information available in the callback, like the subscription
* or other information, you may use a lambda with captures or std::bind.
*
* \param[in] callback functor to be called when a new message is received.
*/
void
set_on_ready_callback(std::function<void(size_t, int)> callback) override
{
if (!callback) {
throw std::invalid_argument(
"The callback passed to set_on_ready_callback "
"is not callable.");
}
// Note: we bind the int identifier argument to this waitable's entity types
auto new_callback =
[callback, this](size_t number_of_events) {
try {
callback(number_of_events, static_cast<int>(EntityType::Subscription));
} catch (const std::exception & exception) {
RCLCPP_ERROR_STREAM(
// TODO(wjwwood): get this class access to the node logger it is associated with
rclcpp::get_logger("rclcpp"),
"rclcpp::SubscriptionIntraProcessBase@" << this <<
" caught " << rmw::impl::cpp::demangle(exception) <<
" exception in user-provided callback for the 'on ready' callback: " <<
exception.what());
} catch (...) {
RCLCPP_ERROR_STREAM(
rclcpp::get_logger("rclcpp"),
"rclcpp::SubscriptionIntraProcessBase@" << this <<
" caught unhandled exception in user-provided callback " <<
"for the 'on ready' callback");
}
};
std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
on_new_message_callback_ = new_callback;
if (unread_count_ > 0) {
if (qos_profile_.history() == HistoryPolicy::KeepAll) {
on_new_message_callback_(unread_count_);
} else {
// Use qos profile depth as upper bound for unread_count_
on_new_message_callback_(std::min(unread_count_, qos_profile_.depth()));
}
unread_count_ = 0;
}
}
/// Unset the callback registered for new messages, if any.
void
clear_on_ready_callback() override
{
std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
on_new_message_callback_ = nullptr;
}
RCLCPP_PUBLIC
std::vector<std::shared_ptr<rclcpp::TimerBase>>
get_timers() const override
{
return {};
}
protected:
std::recursive_mutex on_new_message_callback_mutex_;
std::function<void(size_t)> on_new_message_callback_ {nullptr};
bool on_new_message_callback_disabled_{false};
size_t unread_count_{0};
rclcpp::GuardCondition gc_;
private:
virtual void
trigger_guard_condition() = 0;
void
invoke_on_new_message()
{
std::lock_guard<std::recursive_mutex> lock(this->on_new_message_callback_mutex_);
if (!on_new_message_callback_disabled_) {
if (this->on_new_message_callback_) {
this->on_new_message_callback_(1);
} else {
this->unread_count_++;
}
}
}
private:
std::string topic_name_;
QoS qos_profile_;
};

View File

@@ -15,24 +15,23 @@
#ifndef RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BUFFER_HPP_
#define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BUFFER_HPP_
#include <rmw/rmw.h>
#include <functional>
#include <map>
#include <memory>
#include <stdexcept>
#include <string>
#include <stdexcept>
#include <utility>
#include "rcl/error_handling.h"
#include "rcl/guard_condition.h"
#include "rcl/wait.h"
#include "rclcpp/any_subscription_callback.hpp"
#include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
#include "rclcpp/experimental/create_intra_process_buffer.hpp"
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
#include "rclcpp/experimental/ros_message_intra_process_buffer.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/waitable.hpp"
#include "rclcpp/detail/add_guard_condition_to_rcl_wait_set.hpp"
#include "tracetools/tracetools.h"
namespace rclcpp
@@ -41,24 +40,39 @@ namespace experimental
{
template<
typename MessageT,
typename Alloc = std::allocator<void>,
typename Deleter = std::default_delete<MessageT>
typename SubscribedType,
typename Alloc = std::allocator<SubscribedType>,
typename Deleter = std::default_delete<SubscribedType>,
/// MessageT::ros_message_type if MessageT is a TypeAdapter,
/// otherwise just MessageT.
typename ROSMessageType = SubscribedType
>
class SubscriptionIntraProcessBuffer : public SubscriptionIntraProcessBase
class SubscriptionIntraProcessBuffer : public SubscriptionROSMsgIntraProcessBuffer<ROSMessageType,
typename allocator::AllocRebind<ROSMessageType, Alloc>::allocator_type,
allocator::Deleter<typename allocator::AllocRebind<ROSMessageType, Alloc>::allocator_type,
ROSMessageType>>
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionIntraProcessBuffer)
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
using MessageAlloc = typename MessageAllocTraits::allocator_type;
using ConstMessageSharedPtr = std::shared_ptr<const MessageT>;
using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
using SubscribedTypeAllocatorTraits = allocator::AllocRebind<SubscribedType, Alloc>;
using SubscribedTypeAllocator = typename SubscribedTypeAllocatorTraits::allocator_type;
using SubscribedTypeDeleter = allocator::Deleter<SubscribedTypeAllocator, SubscribedType>;
using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, Alloc>;
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
using ConstMessageSharedPtr = std::shared_ptr<const ROSMessageType>;
using MessageUniquePtr = std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>;
using ConstDataSharedPtr = std::shared_ptr<const SubscribedType>;
using SubscribedTypeUniquePtr = std::unique_ptr<SubscribedType, SubscribedTypeDeleter>;
using BufferUniquePtr = typename rclcpp::experimental::buffers::IntraProcessBuffer<
MessageT,
SubscribedType,
Alloc,
Deleter
SubscribedTypeDeleter
>::UniquePtr;
SubscriptionIntraProcessBuffer(
@@ -67,74 +81,118 @@ public:
const std::string & topic_name,
const rclcpp::QoS & qos_profile,
rclcpp::IntraProcessBufferType buffer_type)
: SubscriptionIntraProcessBase(topic_name, qos_profile)
: SubscriptionROSMsgIntraProcessBuffer<ROSMessageType, ROSMessageTypeAllocator,
ROSMessageTypeDeleter>(
context, topic_name, qos_profile),
subscribed_type_allocator_(*allocator)
{
allocator::set_allocator_for_deleter(&subscribed_type_deleter_, &subscribed_type_allocator_);
// Create the intra-process buffer.
buffer_ = rclcpp::experimental::create_intra_process_buffer<MessageT, Alloc, Deleter>(
buffer_ = rclcpp::experimental::create_intra_process_buffer<SubscribedType, Alloc,
SubscribedTypeDeleter>(
buffer_type,
qos_profile,
allocator);
// Create the guard condition.
rcl_guard_condition_options_t guard_condition_options =
rcl_guard_condition_get_default_options();
gc_ = rcl_get_zero_initialized_guard_condition();
rcl_ret_t ret = rcl_guard_condition_init(
&gc_, context->get_rcl_context().get(), guard_condition_options);
if (RCL_RET_OK != ret) {
throw std::runtime_error(
"SubscriptionIntraProcessBuffer init error initializing guard condition");
}
std::make_shared<Alloc>(subscribed_type_allocator_));
TRACETOOLS_TRACEPOINT(
rclcpp_ipb_to_subscription,
static_cast<const void *>(buffer_.get()),
static_cast<const void *>(this));
}
virtual ~SubscriptionIntraProcessBuffer()
void
add_to_wait_set(rcl_wait_set_t & wait_set) override
{
if (rcl_guard_condition_fini(&gc_) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Failed to destroy guard condition: %s",
rcutils_get_error_string().str);
if (this->buffer_->has_data()) {
this->trigger_guard_condition();
}
detail::add_guard_condition_to_rcl_wait_set(wait_set, this->gc_);
}
bool
is_ready(rcl_wait_set_t * wait_set)
is_ready([[maybe_unused]] const rcl_wait_set_t & wait_set) override
{
(void) wait_set;
return buffer_->has_data();
}
SubscribedTypeUniquePtr
convert_ros_message_to_subscribed_type_unique_ptr(const ROSMessageType & msg)
{
if constexpr (!std::is_same<SubscribedType, ROSMessageType>::value) {
auto ptr = SubscribedTypeAllocatorTraits::allocate(subscribed_type_allocator_, 1);
SubscribedTypeAllocatorTraits::construct(subscribed_type_allocator_, ptr);
rclcpp::TypeAdapter<SubscribedType, ROSMessageType>::convert_to_custom(msg, *ptr);
return SubscribedTypeUniquePtr(ptr, subscribed_type_deleter_);
} else {
throw std::runtime_error(
"convert_ros_message_to_subscribed_type_unique_ptr "
"unexpectedly called without TypeAdapter");
}
}
void
provide_intra_process_message(ConstMessageSharedPtr message)
provide_intra_process_message(ConstMessageSharedPtr message) override
{
if constexpr (std::is_same<SubscribedType, ROSMessageType>::value) {
buffer_->add_shared(std::move(message));
trigger_guard_condition();
} else {
buffer_->add_shared(convert_ros_message_to_subscribed_type_unique_ptr(*message));
trigger_guard_condition();
}
this->invoke_on_new_message();
}
void
provide_intra_process_message(MessageUniquePtr message) override
{
if constexpr (std::is_same<SubscribedType, ROSMessageType>::value) {
buffer_->add_unique(std::move(message));
trigger_guard_condition();
} else {
buffer_->add_unique(convert_ros_message_to_subscribed_type_unique_ptr(*message));
trigger_guard_condition();
}
this->invoke_on_new_message();
}
void
provide_intra_process_data(ConstDataSharedPtr message)
{
buffer_->add_shared(std::move(message));
trigger_guard_condition();
this->invoke_on_new_message();
}
void
provide_intra_process_message(MessageUniquePtr message)
provide_intra_process_data(SubscribedTypeUniquePtr message)
{
buffer_->add_unique(std::move(message));
trigger_guard_condition();
this->invoke_on_new_message();
}
bool
use_take_shared_method() const
use_take_shared_method() const override
{
return buffer_->use_take_shared_method();
}
size_t available_capacity() const override
{
return buffer_->available_capacity();
}
protected:
void
trigger_guard_condition()
trigger_guard_condition() override
{
rcl_ret_t ret = rcl_trigger_guard_condition(&gc_);
(void)ret;
this->gc_.trigger();
}
BufferUniquePtr buffer_;
SubscribedTypeAllocator subscribed_type_allocator_;
SubscribedTypeDeleter subscribed_type_deleter_;
};
} // namespace experimental

View File

@@ -0,0 +1,558 @@
// Copyright 2023 iRobot 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__EXPERIMENTAL__TIMERS_MANAGER_HPP_
#define RCLCPP__EXPERIMENTAL__TIMERS_MANAGER_HPP_
#include <algorithm>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
#include <thread>
#include <utility>
#include <vector>
#include "rclcpp/context.hpp"
#include "rclcpp/timer.hpp"
namespace rclcpp
{
namespace experimental
{
/**
* @brief This class provides a way for storing and executing timer objects.
* It provides APIs to suit the needs of different applications and execution models.
* All public APIs provided by this class are thread-safe.
*
* Timers management
* This class provides APIs to add/remove timers to/from an internal storage.
* It keeps a list of weak pointers from added timers, and locks them only when
* they need to be executed or modified.
* Timers are kept ordered in a binary-heap priority queue.
* Calls to add/remove APIs will temporarily block the execution of the timers and
* will require to reorder the internal priority queue.
* Because of this, they have a not-negligible impact on the performance.
*
* Timers execution
* The most efficient use of this class consists in letting a TimersManager object
* to spawn a thread where timers are monitored and optionally executed.
* This can be controlled via the `start` and `stop` methods.
* Ready timers can either be executed or an on_ready_callback can be used to notify
* other entities that they are ready and need to be executed.
* Other APIs allow to directly execute a given timer.
*
* This class assumes that the `execute_callback()` API of the stored timers is never
* called by other entities, but it can only be called from here.
* If this assumption is not respected, the heap property may be invalidated,
* so timers may be executed out of order, without this object noticing it.
*
*/
class TimersManager
{
public:
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(TimersManager)
/**
* @brief Construct a new TimersManager object
*
* @param context custom context to be used.
* Shared ownership of the context is held until destruction.
* @param on_ready_callback The timers on ready callback. The presence of this function
* indicates what to do when the TimersManager is running and a timer becomes ready.
* The TimersManager is considered "running" when the `start` method has been called.
* If it's callable, it will be invoked instead of the timer callback.
* If it's not callable, then the TimersManager will
* directly execute timers when they are ready.
* All the methods that execute a given timer (e.g. `execute_head_timer`
* or `execute_ready_timer`) without the TimersManager being `running`, i.e.
* without actually explicitly waiting for the timer to become ready, will ignore this
* callback.
*/
RCLCPP_PUBLIC
TimersManager(
std::shared_ptr<rclcpp::Context> context,
std::function<void(const rclcpp::TimerBase *,
const std::shared_ptr<void> &)> on_ready_callback = nullptr);
/**
* @brief Destruct the TimersManager object making sure to stop thread and release memory.
*/
RCLCPP_PUBLIC
~TimersManager();
/**
* @brief Adds a new timer to the storage, maintaining weak ownership of it.
* Function is thread safe and it can be called regardless of the state of the timers thread.
*
* @param timer the timer to add.
* @throws std::invalid_argument if timer is a nullptr.
*/
RCLCPP_PUBLIC
void add_timer(const rclcpp::TimerBase::SharedPtr & timer);
/**
* @brief Remove a single timer from the object storage.
* Will do nothing if the timer was not being stored here.
* Function is thread safe and it can be called regardless of the state of the timers thread.
*
* @param timer the timer to remove.
*/
RCLCPP_PUBLIC
void remove_timer(const rclcpp::TimerBase::SharedPtr & timer);
/**
* @brief Remove all the timers stored in the object.
* Function is thread safe and it can be called regardless of the state of the timers thread.
*/
RCLCPP_PUBLIC
void clear();
/**
* @brief Starts a thread that takes care of executing the timers stored in this object.
* Function will throw an error if the timers thread was already running.
*/
RCLCPP_PUBLIC
void start();
/**
* @brief Stops the timers thread.
* Will do nothing if the timer thread was not running.
*/
RCLCPP_PUBLIC
void stop();
/**
* @brief Get the number of timers that are currently ready.
* This function is thread safe.
*
* @return size_t number of ready timers.
* @throws std::runtime_error if the timers thread was already running.
*/
RCLCPP_PUBLIC
size_t get_number_ready_timers();
/**
* @brief Executes head timer if ready.
* This function is thread safe.
* This function will try to execute the timer callback regardless of whether
* the TimersManager on_ready_callback was passed during construction.
*
* @return true if head timer was ready.
* @throws std::runtime_error if the timers thread was already running.
*/
RCLCPP_PUBLIC
bool execute_head_timer();
/**
* @brief Executes timer identified by its ID.
* This function is thread safe.
* This function will try to execute the timer callback regardless of whether
* the TimersManager on_ready_callback was passed during construction.
*
* @param timer_id the timer ID of the timer to execute
* @param data internal data of the timer
*/
RCLCPP_PUBLIC
void execute_ready_timer(const rclcpp::TimerBase * timer_id, const std::shared_ptr<void> & data);
/**
* @brief Get the amount of time before the next timer triggers.
* This function is thread safe.
*
* @return std::optional<std::chrono::nanoseconds> to wait,
* the returned value could be negative if the timer is already expired
* or std::chrono::nanoseconds::max() if there are no timers stored in the object.
* If the head timer was cancelled, then this will return a nullopt.
* @throws std::runtime_error if the timers thread was already running.
*/
RCLCPP_PUBLIC
std::optional<std::chrono::nanoseconds> get_head_timeout();
private:
RCLCPP_DISABLE_COPY(TimersManager)
using TimerPtr = rclcpp::TimerBase::SharedPtr;
using WeakTimerPtr = rclcpp::TimerBase::WeakPtr;
// Forward declaration
class TimersHeap;
/**
* @brief This class allows to store weak pointers to timers in a heap-like data structure.
* The root of the heap is the timer that triggers first.
* Since this class uses weak ownership, it is not guaranteed that it represents a valid heap
* at any point in time as timers could go out of scope, thus invalidating it.
* The "validate_and_lock" API allows to restore the heap property and also returns a locked version
* of the timers heap.
* This class is not thread safe and requires external mutexes to protect its usage.
*/
class WeakTimersHeap
{
public:
/**
* @brief Add a new timer to the heap. After the addition, the heap property is enforced.
*
* @param timer new timer to add.
* @return true if timer has been added, false if it was already there.
*/
bool add_timer(TimerPtr timer)
{
TimersHeap locked_heap = this->validate_and_lock();
bool added = locked_heap.add_timer(std::move(timer));
if (added) {
// Re-create the weak heap with the new timer added
this->store(locked_heap);
}
return added;
}
/**
* @brief Remove a timer from the heap. After the removal, the heap property is enforced.
*
* @param timer timer to remove.
* @return true if timer has been removed, false if it was not there.
*/
bool remove_timer(TimerPtr timer)
{
TimersHeap locked_heap = this->validate_and_lock();
bool removed = locked_heap.remove_timer(std::move(timer));
if (removed) {
// Re-create the weak heap with the timer removed
this->store(locked_heap);
}
return removed;
}
/**
* @brief Retrieve the timer identified by the key
* @param timer_id The ID of the timer to retrieve.
* @return TimerPtr if there's a timer associated with the ID, nullptr otherwise
*/
TimerPtr get_timer(const rclcpp::TimerBase * timer_id)
{
for (auto & weak_timer : weak_heap_) {
auto timer = weak_timer.lock();
if (timer.get() == timer_id) {
return timer;
}
}
return nullptr;
}
/**
* @brief Returns a const reference to the front element.
*/
const WeakTimerPtr & front() const
{
return weak_heap_.front();
}
/**
* @brief Returns whether the heap is empty or not.
*/
bool empty() const
{
return weak_heap_.empty();
}
/**
* @brief This function restores the current object as a valid heap
* and it returns a locked version of it.
* Timers that went out of scope are removed from the container.
* It is the only public API to access and manipulate the stored timers.
*
* @return TimersHeap owned timers corresponding to the current object
*/
TimersHeap validate_and_lock()
{
TimersHeap locked_heap;
bool any_timer_destroyed = false;
for (auto weak_timer : weak_heap_) {
auto timer = weak_timer.lock();
if (timer) {
// This timer is valid, so add it to the locked heap
// Note: we access friend private `owned_heap_` member field.
locked_heap.owned_heap_.push_back(std::move(timer));
} else {
// This timer went out of scope, so we don't add it to locked heap
// and we mark the corresponding flag.
// It's not needed to erase it from weak heap, as we are going to re-heapify.
// Note: we can't exit from the loop here, as we need to find all valid timers.
any_timer_destroyed = true;
}
}
// If a timer has gone out of scope, then the remaining elements do not represent
// a valid heap anymore. We need to re-heapify the timers heap.
if (any_timer_destroyed) {
locked_heap.heapify();
// Re-create the weak heap now that elements have been heapified again
this->store(locked_heap);
}
return locked_heap;
}
/**
* @brief This function allows to recreate the heap of weak pointers
* from an heap of owned pointers.
* It is required to be called after a locked TimersHeap generated from this object
* has been modified in any way (e.g. timers triggered, added, removed).
*
* @param heap timers heap to store as weak pointers
*/
void store(const TimersHeap & heap)
{
weak_heap_.clear();
// Note: we access friend private `owned_heap_` member field.
for (auto t : heap.owned_heap_) {
weak_heap_.push_back(t);
}
}
/**
* @brief Remove all timers from the heap.
*/
void clear()
{
weak_heap_.clear();
}
private:
std::vector<WeakTimerPtr> weak_heap_;
};
/**
* @brief This class is the equivalent of WeakTimersHeap but with ownership of the timers.
* It can be generated by locking the weak version.
* It provides operations to manipulate the heap.
* This class is not thread safe and requires external mutexes to protect its usage.
*/
class TimersHeap
{
public:
/**
* @brief Try to add a new timer to the heap.
* After the addition, the heap property is preserved.
* @param timer new timer to add.
* @return true if timer has been added, false if it was already there.
*/
bool add_timer(TimerPtr timer)
{
// Nothing to do if the timer is already stored here
auto it = std::find(owned_heap_.begin(), owned_heap_.end(), timer);
if (it != owned_heap_.end()) {
return false;
}
owned_heap_.push_back(std::move(timer));
std::push_heap(owned_heap_.begin(), owned_heap_.end(), timer_greater);
return true;
}
/**
* @brief Try to remove a timer from the heap.
* After the removal, the heap property is preserved.
* @param timer timer to remove.
* @return true if timer has been removed, false if it was not there.
*/
bool remove_timer(TimerPtr timer)
{
// Nothing to do if the timer is not stored here
auto it = std::find(owned_heap_.begin(), owned_heap_.end(), timer);
if (it == owned_heap_.end()) {
return false;
}
owned_heap_.erase(it);
this->heapify();
return true;
}
/**
* @brief Returns a reference to the front element.
* @return reference to front element.
*/
TimerPtr & front()
{
return owned_heap_.front();
}
/**
* @brief Returns a const reference to the front element.
* @return const reference to front element.
*/
const TimerPtr & front() const
{
return owned_heap_.front();
}
/**
* @brief Returns whether the heap is empty or not.
* @return true if the heap is empty.
*/
bool empty() const
{
return owned_heap_.empty();
}
/**
* @brief Returns the size of the heap.
* @return the number of valid timers in the heap.
*/
size_t size() const
{
return owned_heap_.size();
}
/**
* @brief Get the number of timers that are currently ready.
* @return size_t number of ready timers.
*/
size_t get_number_ready_timers() const
{
size_t ready_timers = 0;
for (TimerPtr t : owned_heap_) {
if (t->is_ready()) {
ready_timers++;
}
}
return ready_timers;
}
/**
* @brief Restore a valid heap after the root value has been replaced (e.g. timer triggered).
*/
void heapify_root()
{
// The following code is a more efficient version than doing
// pop_heap, pop_back, push_back, push_heap
// as it removes the need for the last push_heap
// Push the modified element (i.e. the current root) at the bottom of the heap
owned_heap_.push_back(owned_heap_[0]);
// Exchange first and last-1 elements and reheapify
std::pop_heap(owned_heap_.begin(), owned_heap_.end(), timer_greater);
// Remove last element
owned_heap_.pop_back();
}
/**
* @brief Completely restores the structure to a valid heap
*/
void heapify()
{
std::make_heap(owned_heap_.begin(), owned_heap_.end(), timer_greater);
}
/**
* @brief Helper function to clear the "on_reset_callback" on all associated timers.
*/
void clear_timers_on_reset_callbacks()
{
for (TimerPtr & t : owned_heap_) {
t->clear_on_reset_callback();
}
}
/**
* @brief Friend declaration to allow the `validate_and_lock()` function to access the
* underlying heap container
*/
friend TimersHeap WeakTimersHeap::validate_and_lock();
/**
* @brief Friend declaration to allow the `store()` function to access the
* underlying heap container
*/
friend void WeakTimersHeap::store(const TimersHeap & heap);
private:
/**
* @brief Comparison function between timers.
* @return true if `a` triggers after `b`.
*/
static bool timer_greater(TimerPtr a, TimerPtr b)
{
// TODO(alsora): this can cause an error if timers are using different clocks
return a->time_until_trigger() > b->time_until_trigger();
}
std::vector<TimerPtr> owned_heap_;
};
/**
* @brief Implements a loop that keeps executing ready timers.
* This function is executed in the timers thread.
*/
void run_timers();
/**
* @brief Get the amount of time before the next timer triggers.
* This function is not thread safe, acquire a mutex before calling it.
*
* @return std::optional<std::chrono::nanoseconds> to wait,
* the returned value could be negative if the timer is already expired
* or std::chrono::nanoseconds::max() if the heap is empty.
* If the head timer was cancelled, then this will return a nullopt.
* This function is not thread safe, acquire the timers_mutex_ before calling it.
*/
std::optional<std::chrono::nanoseconds> get_head_timeout_unsafe();
/**
* @brief Executes all the timers currently ready when the function is invoked
* while keeping the heap correctly sorted.
* This function is not thread safe, acquire the timers_mutex_ before calling it.
*/
void execute_ready_timers_unsafe();
// Callback to be called when timer is ready
std::function<void(const rclcpp::TimerBase *,
const std::shared_ptr<void> &)> on_ready_callback_ = nullptr;
// Thread used to run the timers execution task
std::thread timers_thread_;
// Protects access to timers
std::mutex timers_mutex_;
// Protects access to stop()
std::mutex stop_mutex_;
// Notifies the timers thread whenever timers are added/removed
std::condition_variable timers_cv_;
// Flag used as predicate by timers_cv_ that denotes one or more timers being added/removed
bool timers_updated_ {false};
// Indicates whether the timers thread is currently running or not
std::atomic<bool> running_ {false};
// Parent context used to understand if ROS is still active
std::shared_ptr<rclcpp::Context> context_;
// Timers heap storage with weak ownership
WeakTimersHeap weak_timers_heap_;
};
} // namespace experimental
} // namespace rclcpp
#endif // RCLCPP__EXPERIMENTAL__TIMERS_MANAGER_HPP_

View File

@@ -80,10 +80,12 @@ struct function_traits<ReturnTypeT (*)(Args ...)>: function_traits<ReturnTypeT(A
// std::bind for object methods
template<typename ClassT, typename ReturnTypeT, typename ... Args, typename ... FArgs>
#if defined _LIBCPP_VERSION // libc++ (Clang)
#if defined DOXYGEN_ONLY
struct function_traits<std::bind<ReturnTypeT (ClassT::*)(Args ...), FArgs ...>>
#elif defined _LIBCPP_VERSION // libc++ (Clang)
struct function_traits<std::__bind<ReturnTypeT (ClassT::*)(Args ...), FArgs ...>>
#elif defined _GLIBCXX_RELEASE // glibc++ (GNU C++ >= 7.1)
struct function_traits<std::_Bind<ReturnTypeT(ClassT::*(FArgs ...))(Args ...)>>
struct function_traits<std::_Bind<ReturnTypeT(ClassT::* (FArgs ...))(Args ...)>>
#elif defined __GLIBCXX__ // glibc++ (GNU C++)
struct function_traits<std::_Bind<std::_Mem_fn<ReturnTypeT (ClassT::*)(Args ...)>(FArgs ...)>>
#elif defined _MSC_VER // MS Visual Studio
@@ -97,10 +99,12 @@ struct function_traits<
// std::bind for object const methods
template<typename ClassT, typename ReturnTypeT, typename ... Args, typename ... FArgs>
#if defined _LIBCPP_VERSION // libc++ (Clang)
#if defined DOXYGEN_ONLY
struct function_traits<std::bind<ReturnTypeT (ClassT::*)(Args ...) const, FArgs ...>>
#elif defined _LIBCPP_VERSION // libc++ (Clang)
struct function_traits<std::__bind<ReturnTypeT (ClassT::*)(Args ...) const, FArgs ...>>
#elif defined _GLIBCXX_RELEASE // glibc++ (GNU C++ >= 7.1)
struct function_traits<std::_Bind<ReturnTypeT(ClassT::*(FArgs ...))(Args ...) const>>
struct function_traits<std::_Bind<ReturnTypeT(ClassT::* (FArgs ...))(Args ...) const>>
#elif defined __GLIBCXX__ // glibc++ (GNU C++)
struct function_traits<std::_Bind<std::_Mem_fn<ReturnTypeT (ClassT::*)(Args ...) const>(FArgs ...)>>
#elif defined _MSC_VER // MS Visual Studio
@@ -114,7 +118,9 @@ struct function_traits<
// std::bind for free functions
template<typename ReturnTypeT, typename ... Args, typename ... FArgs>
#if defined _LIBCPP_VERSION // libc++ (Clang)
#if defined DOXYGEN_ONLY
struct function_traits<std::bind<ReturnTypeT( &)(Args ...), FArgs ...>>
#elif defined _LIBCPP_VERSION // libc++ (Clang)
struct function_traits<std::__bind<ReturnTypeT( &)(Args ...), FArgs ...>>
#elif defined __GLIBCXX__ // glibc++ (GNU C++)
struct function_traits<std::_Bind<ReturnTypeT(*(FArgs ...))(Args ...)>>

View File

@@ -0,0 +1,303 @@
// Copyright 2023 Sony Group 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__GENERIC_CLIENT_HPP_
#define RCLCPP__GENERIC_CLIENT_HPP_
#include <map>
#include <memory>
#include <future>
#include <string>
#include <tuple>
#include <vector>
#include <utility>
#include "rcl/client.h"
#include "rclcpp/client.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rcpputils/shared_library.hpp"
#include "rosidl_typesupport_introspection_cpp/message_introspection.hpp"
namespace rclcpp
{
class GenericClient : public ClientBase
{
public:
using Request = void *; // Deserialized data pointer of request message
using Response = void *; // Deserialized data pointer of response message
using SharedResponse = std::shared_ptr<void>;
using Promise = std::promise<SharedResponse>;
using SharedPromise = std::shared_ptr<Promise>;
using Future = std::future<SharedResponse>;
using SharedFuture = std::shared_future<SharedResponse>;
using CallbackType = std::function<void (SharedFuture)>;
RCLCPP_SMART_PTR_DEFINITIONS(GenericClient)
/// A convenient GenericClient::Future and request id pair.
/**
* Public members:
* - future: a std::future<void *>.
* - request_id: the request id associated with the future.
*
* All the other methods are equivalent to the ones std::future provides.
*/
struct FutureAndRequestId
: detail::FutureAndRequestId<Future>
{
using detail::FutureAndRequestId<Future>::FutureAndRequestId;
/// See std::future::share().
SharedFuture share() noexcept {return this->future.share();}
/// Move constructor.
FutureAndRequestId(FutureAndRequestId && other) noexcept = default;
/// Deleted copy constructor, each instance is a unique owner of the future.
FutureAndRequestId(const FutureAndRequestId & other) = delete;
/// Move assignment.
FutureAndRequestId & operator=(FutureAndRequestId && other) noexcept = default;
/// Deleted copy assignment, each instance is a unique owner of the future.
FutureAndRequestId & operator=(const FutureAndRequestId & other) = delete;
/// Destructor.
~FutureAndRequestId() = default;
};
/// A convenient GenericClient::SharedFuture and request id pair.
/**
* Public members:
* - future: a std::shared_future<SharedResponse>.
* - request_id: the request id associated with the future.
*
* All the other methods are equivalent to the ones std::shared_future provides.
*/
struct SharedFutureAndRequestId
: detail::FutureAndRequestId<std::shared_future<SharedResponse>>
{
using detail::FutureAndRequestId<std::shared_future<SharedResponse>>::FutureAndRequestId;
};
GenericClient(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr & node_graph,
const std::string & service_name,
const std::string & service_type,
rcl_client_options_t & client_options);
RCLCPP_PUBLIC
SharedResponse
create_response() override;
RCLCPP_PUBLIC
std::shared_ptr<rmw_request_id_t>
create_request_header() override;
RCLCPP_PUBLIC
void
handle_response(
const std::shared_ptr<rmw_request_id_t> & request_header,
const std::shared_ptr<void> & response) override;
/// Send a request to the service server.
/**
* This method returns a `FutureAndRequestId` instance
* that can be passed to Executor::spin_until_future_complete() to
* wait until it has been completed.
*
* If the future never completes,
* e.g. the call to Executor::spin_until_future_complete() times out,
* GenericClient::remove_pending_request() must be called to clean the client internal state.
* Not doing so will make the `GenericClient` instance to use more memory each time a response is
* not received from the service server.
*
* ```cpp
* auto future = generic_client->async_send_request(my_request);
* if (
* rclcpp::FutureReturnCode::TIMEOUT ==
* executor->spin_until_future_complete(future, timeout))
* {
* generic_client->remove_pending_request(future);
* // handle timeout
* } else {
* handle_response(future.get());
* }
* ```
*
* \param[in] request request to be send.
* \return a FutureAndRequestId instance.
*/
RCLCPP_PUBLIC
FutureAndRequestId
async_send_request(const Request & request);
/// Send a request to the service server and schedule a callback in the executor.
/**
* Similar to the previous overload, but a callback will automatically be called when a response
* is received.
*
* If the callback is never called, because we never got a reply for the service server,
* remove_pending_request() has to be called with the returned request id or
* prune_pending_requests().
* Not doing so will make the `GenericClient` instance use more memory each time a response is not
* received from the service server.
* In this case, it's convenient to setup a timer to cleanup the pending requests.
*
* \param[in] request request to be send.
* \param[in] cb callback that will be called when we get a response for this request.
* \return the request id representing the request just sent.
*/
template<
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
CallbackT,
CallbackType
>::value
>::type * = nullptr
>
SharedFutureAndRequestId
async_send_request(const Request & request, CallbackT && cb)
{
Promise promise;
auto shared_future = promise.get_future().share();
auto req_id = async_send_request_impl(
request,
std::make_tuple(
CallbackType{std::forward<CallbackT>(cb)},
shared_future,
std::move(promise)));
return SharedFutureAndRequestId{std::move(shared_future), req_id};
}
/// Clean all pending requests older than a time_point.
/**
* \param[in] time_point Requests that were sent before this point are going to be removed.
* \param[inout] pruned_requests Removed requests id will be pushed to the vector
* if a pointer is provided.
* \return number of pending requests that were removed.
*/
template<typename AllocatorT = std::allocator<int64_t>>
size_t
prune_requests_older_than(
std::chrono::time_point<std::chrono::system_clock> time_point,
std::vector<int64_t, AllocatorT> * pruned_requests = nullptr)
{
return detail::prune_requests_older_than_impl(
pending_requests_,
pending_requests_mutex_,
time_point,
pruned_requests);
}
/// Clean all pending requests.
/**
* \return number of pending requests that were removed.
*/
RCLCPP_PUBLIC
size_t
prune_pending_requests();
/// Cleanup a pending request.
/**
* This notifies the client that we have waited long enough for a response from the server
* to come, we have given up and we are not waiting for a response anymore.
*
* Not calling this will make the client start using more memory for each request
* that never got a reply from the server.
*
* \param[in] request_id request id returned by async_send_request().
* \return true when a pending request was removed, false if not (e.g. a response was received).
*/
RCLCPP_PUBLIC
bool
remove_pending_request(
int64_t request_id);
/// Cleanup a pending request.
/**
* Convenient overload, same as:
*
* `GenericClient::remove_pending_request(this, future.request_id)`.
*/
RCLCPP_PUBLIC
bool
remove_pending_request(
const FutureAndRequestId & future);
/// Cleanup a pending request.
/**
* Convenient overload, same as:
*
* `GenericClient::remove_pending_request(this, future.request_id)`.
*/
RCLCPP_PUBLIC
bool
remove_pending_request(
const SharedFutureAndRequestId & future);
/// Take the next response for this client.
/**
* \sa ClientBase::take_type_erased_response().
*
* \param[out] response_out The reference to a Service Response into
* which the middleware will copy the response being taken.
* \param[out] request_header_out The request header to be filled by the
* middleware when taking, and which can be used to associate the response
* to a specific request.
* \returns true if the response was taken, otherwise false.
* \throws rclcpp::exceptions::RCLError based exceptions if the underlying
* rcl function fail.
*/
RCLCPP_PUBLIC
bool
take_response(Response response_out, rmw_request_id_t & request_header_out)
{
return this->take_type_erased_response(response_out, request_header_out);
}
protected:
using CallbackTypeValueVariant = std::tuple<CallbackType, SharedFuture, Promise>;
using CallbackInfoVariant = std::variant<
std::promise<SharedResponse>,
CallbackTypeValueVariant>; // Use variant for extension
RCLCPP_PUBLIC
int64_t
async_send_request_impl(
const Request & request,
CallbackInfoVariant value);
std::optional<CallbackInfoVariant>
get_and_erase_pending_request(
int64_t request_number);
RCLCPP_DISABLE_COPY(GenericClient)
std::map<int64_t, std::pair<
std::chrono::time_point<std::chrono::system_clock>,
CallbackInfoVariant>> pending_requests_;
std::mutex pending_requests_mutex_;
private:
std::shared_ptr<rcpputils::SharedLibrary> ts_lib_;
const rosidl_typesupport_introspection_cpp::MessageMembers * response_members_;
};
} // namespace rclcpp
#endif // RCLCPP__GENERIC_CLIENT_HPP_

View File

@@ -31,6 +31,8 @@
#include "rclcpp/typesupport_helpers.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rmw/rmw.h"
namespace rclcpp
{
@@ -60,7 +62,6 @@ public:
* \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`.
@@ -76,39 +77,13 @@ public:
: 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)),
*rclcpp::get_message_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
options.template to_rcl_publisher_options<rclcpp::SerializedMessage>(qos),
// NOTE(methylDragon): Passing these args separately is necessary for event binding
options.event_callbacks,
options.use_default_callbacks),
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;
@@ -117,9 +92,24 @@ public:
RCLCPP_PUBLIC
void publish(const rclcpp::SerializedMessage & message);
/**
* Publish a rclcpp::SerializedMessage via loaned message after de-serialization.
*
* \param message a serialized message
* \throws anything rclcpp::exceptions::throw_from_rcl_error can show
*/
RCLCPP_PUBLIC
void publish_as_loaned_msg(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_;
void * borrow_loaned_message();
void deserialize_message(
const rmw_serialized_message_t & serialized_message,
void * deserialized_msg);
void publish_loaned_message(void * loaned_message);
};
} // namespace rclcpp

View File

@@ -0,0 +1,308 @@
// Copyright 2024 Sony Group 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__GENERIC_SERVICE_HPP_
#define RCLCPP__GENERIC_SERVICE_HPP_
#include <cstdlib>
#include <functional>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#include <variant>
#include "rclcpp/typesupport_helpers.hpp"
#include "rosidl_runtime_c/service_type_support_struct.h"
#include "rosidl_typesupport_introspection_cpp/identifier.hpp"
#include "rosidl_typesupport_introspection_cpp/service_introspection.hpp"
#include "service.hpp"
namespace rclcpp
{
class GenericService;
class GenericServiceCallback
{
public:
using SharedRequest = std::shared_ptr<void>;
using SharedResponse = std::shared_ptr<void>;
GenericServiceCallback()
: callback_(std::monostate{})
{}
template<
typename CallbackT,
typename std::enable_if_t<!detail::can_be_nullptr<CallbackT>::value, int> = 0>
void
set(CallbackT && callback)
{
// Workaround Windows issue with std::bind
if constexpr (
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrCallback
>::value)
{
callback_.template emplace<SharedPtrCallback>(callback);
} else if constexpr ( // NOLINT, can't satisfy both cpplint and uncrustify
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrWithRequestHeaderCallback
>::value)
{
callback_.template emplace<SharedPtrWithRequestHeaderCallback>(callback);
} else if constexpr ( // NOLINT
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrDeferResponseCallback
>::value)
{
callback_.template emplace<SharedPtrDeferResponseCallback>(callback);
} else if constexpr ( // NOLINT
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrDeferResponseCallbackWithServiceHandle
>::value)
{
callback_.template emplace<SharedPtrDeferResponseCallbackWithServiceHandle>(callback);
} else {
// the else clause is not needed, but anyways we should only be doing this instead
// of all the above workaround ...
callback_ = std::forward<CallbackT>(callback);
}
}
template<
typename CallbackT,
typename std::enable_if_t<detail::can_be_nullptr<CallbackT>::value, int> = 0>
void
set(CallbackT && callback)
{
if (!callback) {
throw std::invalid_argument("AnyServiceCallback::set(): callback cannot be nullptr");
}
// Workaround Windows issue with std::bind
if constexpr (
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrCallback
>::value)
{
callback_.template emplace<SharedPtrCallback>(callback);
} else if constexpr ( // NOLINT
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrWithRequestHeaderCallback
>::value)
{
callback_.template emplace<SharedPtrWithRequestHeaderCallback>(callback);
} else if constexpr ( // NOLINT
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrDeferResponseCallback
>::value)
{
callback_.template emplace<SharedPtrDeferResponseCallback>(callback);
} else if constexpr ( // NOLINT
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrDeferResponseCallbackWithServiceHandle
>::value)
{
callback_.template emplace<SharedPtrDeferResponseCallbackWithServiceHandle>(callback);
} else {
// the else clause is not needed, but anyways we should only be doing this instead
// of all the above workaround ...
callback_ = std::forward<CallbackT>(callback);
}
}
SharedResponse
dispatch(
const std::shared_ptr<rclcpp::GenericService> & service_handle,
const std::shared_ptr<rmw_request_id_t> & request_header,
SharedRequest request,
SharedRequest response)
{
TRACETOOLS_TRACEPOINT(callback_start, static_cast<const void *>(this), false);
if (std::holds_alternative<std::monostate>(callback_)) {
// TODO(ivanpauno): Remove the set method, and force the users of this class
// to pass a callback at construnciton.
throw std::runtime_error{"unexpected request without any callback set"};
}
if (std::holds_alternative<SharedPtrDeferResponseCallback>(callback_)) {
const auto & cb = std::get<SharedPtrDeferResponseCallback>(callback_);
cb(request_header, std::move(request));
return nullptr;
}
if (std::holds_alternative<SharedPtrDeferResponseCallbackWithServiceHandle>(callback_)) {
const auto & cb = std::get<SharedPtrDeferResponseCallbackWithServiceHandle>(callback_);
cb(service_handle, request_header, std::move(request));
return nullptr;
}
if (std::holds_alternative<SharedPtrCallback>(callback_)) {
(void)request_header;
const auto & cb = std::get<SharedPtrCallback>(callback_);
cb(std::move(request), response);
} else if (std::holds_alternative<SharedPtrWithRequestHeaderCallback>(callback_)) {
const auto & cb = std::get<SharedPtrWithRequestHeaderCallback>(callback_);
cb(request_header, std::move(request), response);
}
TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
return response;
}
void register_callback_for_tracing()
{
#ifndef TRACETOOLS_DISABLED
std::visit(
[this](auto && arg) {
if (TRACETOOLS_TRACEPOINT_ENABLED(rclcpp_callback_register)) {
char * symbol = tracetools::get_symbol(arg);
TRACETOOLS_DO_TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
symbol);
std::free(symbol);
}
}, callback_);
#endif // TRACETOOLS_DISABLED
}
private:
using SharedPtrCallback = std::function<void (SharedRequest, SharedResponse)>;
using SharedPtrWithRequestHeaderCallback = std::function<
void (
std::shared_ptr<rmw_request_id_t>,
SharedRequest,
SharedResponse
)>;
using SharedPtrDeferResponseCallback = std::function<
void (
std::shared_ptr<rmw_request_id_t>,
SharedRequest
)>;
using SharedPtrDeferResponseCallbackWithServiceHandle = std::function<
void (
std::shared_ptr<rclcpp::GenericService>,
std::shared_ptr<rmw_request_id_t>,
SharedRequest
)>;
std::variant<
std::monostate,
SharedPtrCallback,
SharedPtrWithRequestHeaderCallback,
SharedPtrDeferResponseCallback,
SharedPtrDeferResponseCallbackWithServiceHandle> callback_;
};
class GenericService
: public ServiceBase,
public std::enable_shared_from_this<GenericService>
{
public:
using Request = void *; // Serialized/Deserialized data pointer of request message
using Response = void *; // Serialized/Deserialized data pointer of response message
using SharedRequest = std::shared_ptr<void>;
using SharedResponse = std::shared_ptr<void>;
using CallbackType = std::function<void (const SharedRequest, SharedResponse)>;
using CallbackWithHeaderType =
std::function<void (const std::shared_ptr<rmw_request_id_t>,
const SharedRequest,
SharedResponse)>;
RCLCPP_SMART_PTR_DEFINITIONS(GenericService)
/// Default constructor.
/**
* The constructor for a Service is almost never called directly.
* Instead, services should be instantiated through the function
* rclcpp::create_service().
*
* \param[in] node_handle NodeBaseInterface pointer that is used in part of the setup.
* \param[in] service_name Name of the topic to publish to.
* \param[in] service_type The name of service type, e.g. "std_srvs/srv/SetBool".
* \param[in] any_callback User defined callback to call when a client request is received.
* \param[in] service_options options for the service.
*/
RCLCPP_PUBLIC
GenericService(
const std::shared_ptr<rcl_node_t> & node_handle,
const std::string & service_name,
const std::string & service_type,
GenericServiceCallback any_callback,
rcl_service_options_t & service_options);
GenericService() = delete;
RCLCPP_PUBLIC
virtual ~GenericService() {}
/// Take the next request from the service.
/**
* \sa ServiceBase::take_type_erased_request().
*
* \param[out] request_out The reference to a service deserialized request object
* into which the middleware will copy the taken request.
* \param[out] request_id_out The output id for the request which can be used
* to associate response with this request in the future.
* \returns true if the request was taken, otherwise false.
* \throws rclcpp::exceptions::RCLError based exceptions if the underlying
* rcl calls fail.
*/
RCLCPP_PUBLIC
bool
take_request(SharedRequest & request_out, rmw_request_id_t & request_id_out);
RCLCPP_PUBLIC
std::shared_ptr<void>
create_request() override;
RCLCPP_PUBLIC
std::shared_ptr<void>
create_response();
RCLCPP_PUBLIC
std::shared_ptr<rmw_request_id_t>
create_request_header() override;
RCLCPP_PUBLIC
void
handle_request(
const std::shared_ptr<rmw_request_id_t> & request_header,
const std::shared_ptr<void> & request) override;
RCLCPP_PUBLIC
void
send_response(rmw_request_id_t & req_id, SharedResponse & response);
private:
RCLCPP_DISABLE_COPY(GenericService)
GenericServiceCallback any_callback_;
std::shared_ptr<rcpputils::SharedLibrary> ts_lib_;
const rosidl_typesupport_introspection_cpp::MessageMembers * request_members_;
const rosidl_typesupport_introspection_cpp::MessageMembers * response_members_;
};
} // namespace rclcpp
#endif // RCLCPP__GENERIC_SERVICE_HPP_

View File

@@ -74,51 +74,31 @@ public:
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,
AnySubscriptionCallback<rclcpp::SerializedMessage, AllocatorT> callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options)
: SubscriptionBase(
node_base,
*rclcpp::get_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
*rclcpp::get_message_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
topic_name,
options.template to_rcl_subscription_options<rclcpp::SerializedMessage>(qos),
true),
callback_(callback),
force_cpu_buffer_backend_(options).to_rcl_subscription_options(qos),
options.event_callbacks,
options.use_default_callbacks,
DeliveredMessageKind::SERIALIZED_MESSAGE),
any_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);
}
TRACETOOLS_TRACEPOINT(
rclcpp_subscription_init,
static_cast<const void *>(get_subscription_handle().get()),
static_cast<const void *>(this));
TRACETOOLS_TRACEPOINT(
rclcpp_subscription_callback_added,
static_cast<const void *>(this),
static_cast<const void *>(&any_callback_));
#ifndef TRACETOOLS_DISABLED
any_callback_.register_callback_for_tracing();
#endif
}
RCLCPP_PUBLIC
@@ -131,6 +111,26 @@ public:
RCLCPP_PUBLIC
std::shared_ptr<rclcpp::SerializedMessage> create_serialized_message() override;
/// Disable callbacks from being called
/**
* This method will block, until any subscription's callbacks provided during construction
* currently being executed are finished.
* \note This method also temporary removes the on new message callback and all
* on new event callbacks from the rmw layer to prevent them from being called. However, this
* method will not block and wait until the currently executing on_new_[message]event callbacks
* are finished.
*/
RCLCPP_PUBLIC
void disable_callbacks() override;
/// Enable the callbacks to be called
/**
* This method is thread safe, and provides a safe way to atomically enable the callbacks
* in a multithreaded environment.
*/
RCLCPP_PUBLIC
void enable_callbacks() override;
/// Cast the message to a rclcpp::SerializedMessage and call the callback.
RCLCPP_PUBLIC
void handle_message(
@@ -155,10 +155,45 @@ public:
RCLCPP_PUBLIC
void return_serialized_message(std::shared_ptr<rclcpp::SerializedMessage> & message) override;
// DYNAMIC TYPE ==================================================================================
RCLCPP_PUBLIC
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr get_shared_dynamic_message_type()
override;
RCLCPP_PUBLIC
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr get_shared_dynamic_message() override;
RCLCPP_PUBLIC
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
get_shared_dynamic_serialization_support() override;
RCLCPP_PUBLIC
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr create_dynamic_message() override;
RCLCPP_PUBLIC
void return_dynamic_message(
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message) override;
RCLCPP_PUBLIC
void handle_dynamic_message(
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
const rclcpp::MessageInfo & message_info) override;
private:
RCLCPP_DISABLE_COPY(GenericSubscription)
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback_;
template<typename AllocatorT>
static rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>
force_cpu_buffer_backend_(
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options)
{
auto opts = options;
opts.acceptable_buffer_backends = "cpu";
return opts;
}
AnySubscriptionCallback<rclcpp::SerializedMessage, std::allocator<void>> any_callback_;
// The type support library should stay loaded, so it is stored in the GenericSubscription
std::shared_ptr<rcpputils::SharedLibrary> ts_lib_;
};

View File

@@ -28,7 +28,17 @@
namespace rclcpp
{
/// Specialization for when MessageT is an actual ROS message type.
#ifdef DOXYGEN_ONLY
/// Returns the message type support for the given `MessageT` type.
/**
* \tparam MessageT an actual ROS message type or an adapted type using `rclcpp::TypeAdapter`
*/
template<typename MessageT>
constexpr const rosidl_message_type_support_t & get_message_type_support_handle();
#else
template<typename MessageT>
constexpr
typename std::enable_if_t<
@@ -44,7 +54,6 @@ get_message_type_support_handle()
return *handle;
}
/// Specialization for when MessageT is an adapted type using rclcpp::TypeAdapter.
template<typename AdaptedType>
constexpr
typename std::enable_if_t<
@@ -63,12 +72,9 @@ get_message_type_support_handle()
return *handle;
}
/// Specialization for when MessageT is not a ROS message nor an adapted type.
/**
* This specialization is a pass through runtime check, which allows a better
* static_assert to catch this issue further down the line.
* This should never get to be called in practice, and is purely defensive.
*/
// This specialization is a pass through runtime check, which allows a better
// static_assert to catch this issue further down the line.
// This should never get to be called in practice, and is purely defensive.
template<
typename AdaptedType
>
@@ -85,6 +91,8 @@ get_message_type_support_handle()
"should never be called");
}
#endif
} // namespace rclcpp
#endif // RCLCPP__GET_MESSAGE_TYPE_SUPPORT_HANDLE_HPP_

View File

@@ -24,6 +24,7 @@
#include "rcl/guard_condition.h"
#include "rcl/wait.h"
#include "rclcpp/context.hpp"
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -127,6 +128,11 @@ public:
* If start_if_not_started() was never called, this function still succeeds,
* but start_if_not_started() still cannot be called after this function.
*
* Note that if you override this method, but leave shutdown to be called in
* the destruction of this base class, it will not call the overridden
* version from your base class.
* So you need to ensure you call your class's shutdown() in its destructor.
*
* \throws rclcpp::execptions::RCLError from rcl_guard_condition_fini()
* \throws rclcpp::execptions::RCLError from rcl_wait_set_fini()
* \throws std::system_error anything std::mutex::lock() throws
@@ -148,6 +154,12 @@ public:
bool
is_shutdown();
/// Return true if the graph listener was started.
RCLCPP_PUBLIC
virtual
bool
is_started();
protected:
/// Main function for the listening thread.
RCLCPP_PUBLIC
@@ -175,7 +187,6 @@ private:
void
__shutdown();
std::weak_ptr<rclcpp::Context> weak_parent_context_;
std::shared_ptr<rcl_context_t> rcl_parent_context_;
std::thread listener_thread_;
@@ -187,7 +198,7 @@ private:
mutable std::mutex node_graph_interfaces_mutex_;
std::vector<rclcpp::node_interfaces::NodeGraphInterface *> node_graph_interfaces_;
rcl_guard_condition_t interrupt_guard_condition_ = rcl_get_zero_initialized_guard_condition();
rclcpp::GuardCondition interrupt_guard_condition_;
rcl_wait_set_t wait_set_ = rcl_get_zero_initialized_wait_set();
};

View File

@@ -40,30 +40,34 @@ public:
* Defaults to using the global default context singleton.
* Shared ownership of the context is held with the guard condition until
* destruction.
* \param[in] guard_condition_options Optional guard condition options to be used.
* Defaults to using the default guard condition options.
* \throws std::invalid_argument if the context is nullptr.
* \throws rclcpp::exceptions::RCLError based exceptions when underlying
* rcl functions fail.
*/
RCLCPP_PUBLIC
explicit GuardCondition(
rclcpp::Context::SharedPtr context =
rclcpp::contexts::get_global_default_context());
const rclcpp::Context::SharedPtr & context =
rclcpp::contexts::get_global_default_context(),
rcl_guard_condition_options_t guard_condition_options =
rcl_guard_condition_get_default_options());
RCLCPP_PUBLIC
virtual
~GuardCondition();
/// Return the context used when creating this guard condition.
/// Return the underlying rcl guard condition structure.
RCLCPP_PUBLIC
rclcpp::Context::SharedPtr
get_context() const;
rcl_guard_condition_t &
get_rcl_guard_condition();
/// Return the underlying rcl guard condition structure.
RCLCPP_PUBLIC
const rcl_guard_condition_t &
get_rcl_guard_condition() const;
/// Notify the wait set waiting on this condition, if any, that the condition had been met.
/// Signal that the condition has been met, notifying both the wait set and listeners, if any.
/**
* This function is thread-safe, and may be called concurrently with waiting
* on this guard condition in a wait set.
@@ -89,10 +93,44 @@ public:
bool
exchange_in_use_by_wait_set_state(bool in_use_state);
/// Adds the guard condition to a waitset
/**
* This function is thread-safe.
* \param[in] wait_set pointer to a wait set where to add the guard condition
*/
RCLCPP_PUBLIC
void
add_to_wait_set(rcl_wait_set_t & wait_set);
/// Set a callback to be called whenever the guard condition is triggered.
/**
* The callback receives a size_t which is the number of times the guard condition was triggered
* since the last time this callback was called.
* Normally this is 1, but can be > 1 if the guard condition was triggered before any
* callback was set.
*
* Calling it again will clear any previously set callback.
*
* This function is thread-safe.
*
* If you want more information available in the callback, like the guard condition
* or other information, you may use a lambda with captures or std::bind.
*
* \param[in] callback functor to be called when the guard condition is triggered
*/
RCLCPP_PUBLIC
void
set_on_trigger_callback(const std::function<void(size_t)> & callback);
protected:
rclcpp::Context::SharedPtr context_;
rcl_guard_condition_t rcl_guard_condition_;
std::atomic<bool> in_use_by_wait_set_{false};
std::recursive_mutex reentrant_mutex_;
std::function<void(size_t)> on_trigger_callback_{nullptr};
size_t unread_count_{0};
// the type of wait_set_ is actually rcl_wait_set_t *, but it's never
// dereferenced, only compared to, so make it void * to avoid accidental use
void * wait_set_{nullptr};
};
} // namespace rclcpp

View File

@@ -29,7 +29,7 @@ class InitOptions
{
public:
/// If true, the context will be shutdown on SIGINT by the signal handler (if it was installed).
bool shutdown_on_sigint = true;
bool shutdown_on_signal = true;
/// Constructor
/**

View File

@@ -31,21 +31,20 @@ namespace rclcpp
template<typename MessageT, typename AllocatorT = std::allocator<void>>
class LoanedMessage
{
public:
using MessageAllocatorTraits = rclcpp::allocator::AllocRebind<MessageT, AllocatorT>;
using MessageAllocator = typename MessageAllocatorTraits::allocator_type;
public:
/// Constructor of the LoanedMessage class.
/**
* The constructor of this class allocates memory for a given message type
* and associates this with a given publisher.
*
* Given the publisher instance, a case differentiation is being performaned
* which decides whether the underlying middleware is able to allocate the appropriate
* memory for this message type or not.
* In the case that the middleware can not loan messages, the passed in allocator instance
* is being used to allocate the message within the scope of this class.
* Otherwise, the allocator is being ignored and the allocation is solely performaned
* The underlying middleware is queried to determine whether it is able to allocate the
* appropriate memory for this message type or not.
* In the case that the middleware cannot loan messages, the passed in allocator instance
* is used to allocate the message within the scope of this class.
* Otherwise, the allocator is ignored and the allocation is solely performed
* in the underlying middleware with its appropriate allocation strategy.
* The need for this arises as the user code can be written explicitly targeting a middleware
* capable of loaning messages.
@@ -53,12 +52,12 @@ public:
* a middleware which doesn't support message loaning in which case the allocator will be used.
*
* \param[in] pub rclcpp::Publisher instance to which the memory belongs
* \param[in] allocator Allocator instance in case middleware can not allocate messages
* \param[in] allocator Allocator instance in case middleware cannot allocate messages
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
*/
LoanedMessage(
const rclcpp::PublisherBase & pub,
std::allocator<MessageT> allocator)
MessageAllocator allocator)
: pub_(pub),
message_(nullptr),
message_allocator_(std::move(allocator))
@@ -82,42 +81,14 @@ public:
}
}
/// Constructor of the LoanedMessage class.
/**
* The constructor of this class allocates memory for a given message type
* and associates this with a given publisher.
*
* Given the publisher instance, a case differentiation is being performaned
* which decides whether the underlying middleware is able to allocate the appropriate
* memory for this message type or not.
* In the case that the middleware can not loan messages, the passed in allocator instance
* is being used to allocate the message within the scope of this class.
* Otherwise, the allocator is being ignored and the allocation is solely performaned
* in the underlying middleware with its appropriate allocation strategy.
* The need for this arises as the user code can be written explicitly targeting a middleware
* capable of loaning messages.
* However, this user code is ought to be usable even when dynamically linked against
* a middleware which doesn't support message loaning in which case the allocator will be used.
*
* \param[in] pub rclcpp::Publisher instance to which the memory belongs
* \param[in] allocator Allocator instance in case middleware can not allocate messages
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
*/
[[
deprecated("used the LoanedMessage constructor that does not use a shared_ptr to the allocator")
]]
LoanedMessage(
const rclcpp::PublisherBase * pub,
std::shared_ptr<std::allocator<MessageT>> allocator)
: LoanedMessage(*pub, *allocator)
{}
/// Move semantic for RVO
LoanedMessage(LoanedMessage<MessageT> && other)
: pub_(std::move(other.pub_)),
message_(std::move(other.message_)),
message_allocator_(std::move(other.message_allocator_))
{}
{
other.message_ = nullptr;
}
/// Destructor of the LoanedMessage class.
/**

View File

@@ -15,8 +15,10 @@
#ifndef RCLCPP__LOGGER_HPP_
#define RCLCPP__LOGGER_HPP_
#include <filesystem>
#include <memory>
#include <string>
#include <utility>
#include "rclcpp/visibility_control.hpp"
@@ -79,14 +81,14 @@ 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.
* see 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();
std::filesystem::path
get_log_directory();
class Logger
{
@@ -122,11 +124,9 @@ private:
: name_(new std::string(name)) {}
std::shared_ptr<const std::string> name_;
std::shared_ptr<std::pair<std::string, std::string>> logger_sublogger_pairname_ = nullptr;
public:
RCLCPP_PUBLIC
Logger(const Logger &) = default;
/// Get the name of this logger.
/**
* \return the full name of the logger including any prefixes, or
@@ -157,13 +157,7 @@ public:
*/
RCLCPP_PUBLIC
Logger
get_child(const std::string & suffix)
{
if (!name_) {
return Logger();
}
return Logger(*name_ + "." + suffix);
}
get_child(const std::string & suffix);
/// Set level for current logger.
/**
@@ -174,6 +168,24 @@ public:
RCLCPP_PUBLIC
void
set_level(Level level);
/// Get effective level for current logger.
/**
* The effective level is determined as the severity level of
* the logger if it is set, otherwise it is the first specified severity
* level of the logger's ancestors, starting with its closest ancestor.
* The ancestor hierarchy is signified by logger names being separated by dots:
* a logger named `x` is an ancestor of `x.y`, and both `x` and `x.y` are
* ancestors of `x.y.z`, etc.
* If the level has not been set for the logger nor any of its
* ancestors, the default level is used.
*
* \throws rclcpp::exceptions::RCLError if any error happens.
* \return Level for the current logger.
*/
RCLCPP_PUBLIC
Level
get_effective_level() const;
};
} // namespace rclcpp

View File

@@ -0,0 +1,983 @@
// Copyright 2017 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__LOGGING_HPP_
#define RCLCPP__LOGGING_HPP_
#include <sstream>
#include <type_traits>
#include "rclcpp/logger.hpp"
#include "rcutils/logging_macros.h"
// These are used for compiling out logging macros lower than a minimum severity.
#define RCLCPP_LOG_MIN_SEVERITY_DEBUG 0
#define RCLCPP_LOG_MIN_SEVERITY_INFO 1
#define RCLCPP_LOG_MIN_SEVERITY_WARN 2
#define RCLCPP_LOG_MIN_SEVERITY_ERROR 3
#define RCLCPP_LOG_MIN_SEVERITY_FATAL 4
#define RCLCPP_LOG_MIN_SEVERITY_NONE 5
#define RCLCPP_STATIC_ASSERT_LOGGER(logger) \
do { \
static_assert( \
::std::is_convertible_v<decltype(logger), ::rclcpp::Logger>, \
"First argument to logging macros must be an rclcpp::Logger"); \
} while (0)
/**
* \def RCLCPP_LOG
* Log a message with given severity.
* \param logger The `rclcpp::Logger` to use
* \param ... The format string, followed by the variable arguments for the format string.
*/
#define RCLCPP_LOG(severity, logger, ...) \
do { \
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
RCUTILS_LOG_NAMED(severity, (logger).get_name(), __VA_ARGS__); \
} while (0)
/**
* \def RCLCPP_LOG_ONCE
* Log a message with given severity with the following condition:
* - All log calls except the first one are ignored.
*
* \param logger The `rclcpp::Logger` to use
* \param ... The format string, followed by the variable arguments for the format string.
*/
#define RCLCPP_LOG_ONCE(severity, logger, ...) \
do { \
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
RCUTILS_LOG_ONCE_NAMED(severity, (logger).get_name(), __VA_ARGS__); \
} while (0)
/**
* \def RCLCPP_LOG_EXPRESSION
* Log a message with given severity with the following condition:
* - Log calls are ignored when the expression evaluates to false.
*
* \param logger The `rclcpp::Logger` to use
* \param expression The expression determining if the message should be logged
* \param ... The format string, followed by the variable arguments for the format string.
*/
#define RCLCPP_LOG_EXPRESSION(severity, logger, expression, ...) \
do { \
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
RCUTILS_LOG_EXPRESSION_NAMED(severity, expression, (logger).get_name(), __VA_ARGS__); \
} while (0)
/**
* \def RCLCPP_LOG_FUNCTION
* Log a message with given severity with the following condition:
* - Log calls are ignored when the function returns false.
*
* \param logger The `rclcpp::Logger` to use
* \param function The functions return value determines if the message should be logged
* \param ... The format string, followed by the variable arguments for the format string.
*/
#define RCLCPP_LOG_FUNCTION(severity, logger, function, ...) \
do { \
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
RCUTILS_LOG_FUNCTION_NAMED(severity, function, (logger).get_name(), __VA_ARGS__); \
} while (0)
/**
* \def RCLCPP_LOG_SKIPFIRST
* Log a message with given severity with the following condition:
* - The first log call is ignored but all subsequent calls are processed.
*
* \param logger The `rclcpp::Logger` to use
* \param ... The format string, followed by the variable arguments for the format string.
*/
#define RCLCPP_LOG_SKIPFIRST(severity, logger, ...) \
do { \
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
RCUTILS_LOG_SKIPFIRST_NAMED(severity, (logger).get_name(), __VA_ARGS__); \
} while (0)
#define RCLCPP_LOG_TIME_POINT_FUNC(clock) \
[&c = clock](rcutils_time_point_value_t * time_point)->rcutils_ret_t { \
try { \
*time_point = c.now().nanoseconds(); \
} catch (...) { \
RCUTILS_SAFE_FWRITE_TO_STDERR( \
"[rclcpp|logging.hpp] RCLCPP_DEBUG_THROTTLE could not get current time stamp\n"); \
return RCUTILS_RET_ERROR; \
} \
return RCUTILS_RET_OK; \
}
/**
* \def RCLCPP_LOG_THROTTLE
* Log a message with given severity with the following condition:
* - Log calls are ignored if the last logged message is not longer ago than the specified duration.
*
* \param logger The `rclcpp::Logger` to use
* \param clock rclcpp::Clock that will be used to get the time point.
* \param duration The duration of the throttle interval as an integral value in milliseconds.
* \param ... The format string, followed by the variable arguments for the format string.
*/
#define RCLCPP_LOG_THROTTLE(severity, logger, clock, duration, ...) \
do { \
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
RCUTILS_LOG_THROTTLE_NAMED( \
severity, \
RCLCPP_LOG_TIME_POINT_FUNC(clock), \
duration, \
(logger).get_name(), \
__VA_ARGS__); \
} while (0)
/**
* \def RCLCPP_LOG_SKIPFIRST_THROTTLE
* Log a message with given severity with the following conditions:
* - The first log call is ignored but all subsequent calls are processed.
* - Log calls are ignored if the last logged message is not longer ago than the specified duration.
*
* \param logger The `rclcpp::Logger` to use
* \param clock rclcpp::Clock that will be used to get the time point.
* \param duration The duration of the throttle interval as an integral value in milliseconds.
* \param ... The format string, followed by the variable arguments for the format string.
*/
#define RCLCPP_LOG_SKIPFIRST_THROTTLE(severity, logger, clock, duration, ...) \
do { \
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
RCUTILS_LOG_SKIPFIRST_THROTTLE_NAMED( \
severity, \
RCLCPP_LOG_TIME_POINT_FUNC(clock), \
duration, \
(logger).get_name(), \
__VA_ARGS__); \
} while (0)
/**
* \def RCLCPP_LOG_STREAM
* Log a message with given severity.
*
* \param logger The `rclcpp::Logger` to use
* \param stream_arg The argument << into a stringstream
*/
#define RCLCPP_LOG_STREAM(severity, logger, stream_arg) \
do { \
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
std::stringstream rclcpp_stream_ss_; \
rclcpp_stream_ss_ << stream_arg; \
RCUTILS_LOG_NAMED(severity, (logger).get_name(), "%s", rclcpp_stream_ss_.str().c_str()); \
} while (0)
/**
* \def RCLCPP_LOG_STREAM_ONCE
* Log a message with given severity with the following condition:
* - All log calls except the first one are ignored.
*
* \param logger The `rclcpp::Logger` to use
* \param stream_arg The argument << into a stringstream
*/
#define RCLCPP_LOG_STREAM_ONCE(severity, logger, stream_arg) \
do { \
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
std::stringstream rclcpp_stream_ss_; \
rclcpp_stream_ss_ << stream_arg; \
RCUTILS_LOG_ONCE_NAMED(severity, (logger).get_name(), "%s", rclcpp_stream_ss_.str().c_str()); \
} while (0)
/**
* \def RCLCPP_LOG_STREAM_EXPRESSION
* Log a message with given severity with the following condition:
* - Log calls are being ignored when the expression evaluates to false.
*
* \param logger The `rclcpp::Logger` to use
* \param expression The expression determining if the message should be logged
* \param stream_arg The argument << into a stringstream
*/
#define RCLCPP_LOG_STREAM_EXPRESSION(severity, logger, expression, stream_arg) \
do { \
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
std::stringstream rclcpp_stream_ss_; \
rclcpp_stream_ss_ << stream_arg; \
RCUTILS_LOG_EXPRESSION_NAMED( \
severity, \
expression, \
(logger).get_name(), \
"%s", rclcpp_stream_ss_.str().c_str()); \
} while (0)
/**
* \def RCLCPP_LOG_STREAM_FUNCTION
* Log a message with given severity with the following condition:
* - Log calls are being ignored when the function returns false.
*
* \param logger The `rclcpp::Logger` to use
* \param function The functions return value determines if the message should be logged
* \param stream_arg The argument << into a stringstream
*/
#define RCLCPP_LOG_STREAM_FUNCTION(severity, logger, function, stream_arg) \
do { \
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
std::stringstream rclcpp_stream_ss_; \
rclcpp_stream_ss_ << stream_arg; \
RCUTILS_LOG_FUNCTION_NAMED( \
severity, \
function, \
(logger).get_name(), \
"%s", rclcpp_stream_ss_.str().c_str()); \
} while (0)
/**
* \def RCLCPP_LOG_STREAM_SKIPFIRST
* Log a message with given severity with the following condition:
* - The first log call is ignored but all subsequent calls are processed.
*
* \param logger The `rclcpp::Logger` to use
* \param stream_arg The argument << into a stringstream
*/
#define RCLCPP_LOG_STREAM_SKIPFIRST(severity, logger, stream_arg) \
do { \
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
std::stringstream rclcpp_stream_ss_; \
rclcpp_stream_ss_ << stream_arg; \
RCUTILS_LOG_SKIPFIRST_NAMED( \
severity, \
(logger).get_name(), \
"%s", rclcpp_stream_ss_.str().c_str()); \
} while (0)
/**
* \def RCLCPP_LOG_STREAM_THROTTLE
* Log a message with given severity with the following condition:
* - Log calls are ignored if the last logged message is not longer ago than the specified duration.
*
* \param logger The `rclcpp::Logger` to use
* \param clock rclcpp::Clock that will be used to get the time point.
* \param duration The duration of the throttle interval as an integral value in milliseconds.
* \param stream_arg The argument << into a stringstream
*/
#define RCLCPP_LOG_STREAM_THROTTLE(severity, logger, clock, duration, stream_arg) \
do { \
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
std::stringstream rclcpp_stream_ss_; \
rclcpp_stream_ss_ << stream_arg; \
RCUTILS_LOG_THROTTLE_NAMED( \
severity, \
RCLCPP_LOG_TIME_POINT_FUNC(clock), \
duration, \
(logger).get_name(), \
"%s", rclcpp_stream_ss_.str().c_str()); \
} while (0)
/**
* \def RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE
* Log a message with given severity with the following conditions:
* - The first log call is ignored but all subsequent calls are processed.
* - Log calls are ignored if the last logged message is not longer ago than the specified duration.
*
* \param logger The `rclcpp::Logger` to use
* \param clock rclcpp::Clock that will be used to get the time point.
* \param duration The duration of the throttle interval as an integral value in milliseconds.
* \param stream_arg The argument << into a stringstream
*/
#define RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE(severity, logger, clock, duration, stream_arg) \
do { \
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
std::stringstream rclcpp_stream_ss_; \
rclcpp_stream_ss_ << stream_arg; \
RCUTILS_LOG_SKIPFIRST_THROTTLE_NAMED( \
severity, \
RCLCPP_LOG_TIME_POINT_FUNC(clock), \
duration, \
(logger).get_name(), \
"%s", rclcpp_stream_ss_.str().c_str()); \
} while (0)
/**
* \def RCLCPP_LOG_MIN_SEVERITY
* Define RCLCPP_LOG_MIN_SEVERITY=RCLCPP_LOG_MIN_SEVERITY_[DEBUG|INFO|WARN|ERROR|FATAL]
* in your build options to compile out anything below that severity.
* Use RCLCPP_LOG_MIN_SEVERITY_NONE to compile out all macros.
*/
#ifndef RCLCPP_LOG_MIN_SEVERITY
#define RCLCPP_LOG_MIN_SEVERITY RCLCPP_LOG_MIN_SEVERITY_DEBUG
#endif
/** @name Logging macros for severity DEBUG.
*/
#if (RCLCPP_LOG_MIN_SEVERITY > RCLCPP_LOG_MIN_SEVERITY_DEBUG)
// empty logging macros for severity DEBUG when being disabled at compile time
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_DEBUG(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_DEBUG_ONCE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_DEBUG_EXPRESSION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_DEBUG_FUNCTION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_DEBUG_SKIPFIRST(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_DEBUG_THROTTLE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_DEBUG_SKIPFIRST_THROTTLE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_DEBUG_STREAM(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_DEBUG_STREAM_ONCE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_DEBUG_STREAM_EXPRESSION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_DEBUG_STREAM_FUNCTION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_DEBUG_STREAM_SKIPFIRST(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_DEBUG_STREAM_THROTTLE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_DEBUG_STREAM_SKIPFIRST_THROTTLE(...)
#else
/**
* \def RCLCPP_DEBUG
* \copydoc RCLCPP_LOG
*/
#define RCLCPP_DEBUG(logger, ...) RCLCPP_LOG(RCUTILS_LOG_SEVERITY_DEBUG, logger, __VA_ARGS__)
/**
* \def RCLCPP_DEBUG_ONCE
* \copydoc RCLCPP_LOG_ONCE
*/
#define RCLCPP_DEBUG_ONCE(logger, ...) \
RCLCPP_LOG_ONCE(RCUTILS_LOG_SEVERITY_DEBUG, logger, __VA_ARGS__)
/**
* \def RCLCPP_DEBUG_EXPRESSION
* \copydoc RCLCPP_LOG_EXPRESSION
*/
#define RCLCPP_DEBUG_EXPRESSION(logger, expression, ...) \
RCLCPP_LOG_EXPRESSION(RCUTILS_LOG_SEVERITY_DEBUG, logger, expression, __VA_ARGS__)
/**
* \def RCLCPP_DEBUG_FUNCTION
* \copydoc RCLCPP_LOG_FUNCTION
*/
#define RCLCPP_DEBUG_FUNCTION(logger, function, ...) \
RCLCPP_LOG_FUNCTION(RCUTILS_LOG_SEVERITY_DEBUG, logger, function, __VA_ARGS__)
/**
* \def RCLCPP_DEBUG_SKIPFIRST
* \copydoc RCLCPP_LOG_SKIPFIRST
*/
#define RCLCPP_DEBUG_SKIPFIRST(logger, ...) \
RCLCPP_LOG_SKIPFIRST(RCUTILS_LOG_SEVERITY_DEBUG, logger, __VA_ARGS__)
/**
* \def RCLCPP_DEBUG_THROTTLE
* \copydoc RCLCPP_LOG_THROTTLE
*/
#define RCLCPP_DEBUG_THROTTLE(logger, clock, duration, ...) \
RCLCPP_LOG_THROTTLE(RCUTILS_LOG_SEVERITY_DEBUG, logger, clock, duration, __VA_ARGS__)
/**
* \def RCLCPP_DEBUG_SKIPFIRST_THROTTLE
* \copydoc RCLCPP_LOG_SKIPFIRST_THROTTLE
*/
#define RCLCPP_DEBUG_SKIPFIRST_THROTTLE(logger, clock, duration, ...) \
RCLCPP_LOG_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_DEBUG, logger, clock, duration, __VA_ARGS__)
/**
* \def RCLCPP_DEBUG_STREAM
* \copydoc RCLCPP_LOG_STREAM
*/
#define RCLCPP_DEBUG_STREAM(logger, stream_arg) \
RCLCPP_LOG_STREAM(RCUTILS_LOG_SEVERITY_DEBUG, logger, stream_arg)
/**
* \def RCLCPP_DEBUG_STREAM_ONCE
* \copydoc RCLCPP_LOG_STREAM_ONCE
*/
#define RCLCPP_DEBUG_STREAM_ONCE(logger, stream_arg) \
RCLCPP_LOG_STREAM_ONCE(RCUTILS_LOG_SEVERITY_DEBUG, logger, stream_arg)
/**
* \def RCLCPP_DEBUG_STREAM_EXPRESSION
* \copydoc RCLCPP_LOG_STREAM_EXPRESSION
*/
#define RCLCPP_DEBUG_STREAM_EXPRESSION(logger, expression, stream_arg) \
RCLCPP_LOG_STREAM_EXPRESSION(RCUTILS_LOG_SEVERITY_DEBUG, logger, expression, stream_arg)
/**
* \def RCLCPP_DEBUG_STREAM_FUNCTION
* \copydoc RCLCPP_LOG_STREAM_FUNCTION
*/
#define RCLCPP_DEBUG_STREAM_FUNCTION(logger, function, stream_arg) \
RCLCPP_LOG_STREAM_FUNCTION(RCUTILS_LOG_SEVERITY_DEBUG, logger, function, stream_args)
/**
* \def RCLCPP_DEBUG_STREAM_SKIPFIRST
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST
*/
#define RCLCPP_DEBUG_STREAM_SKIPFIRST(logger, stream_arg) \
RCLCPP_LOG_STREAM_SKIPFIRST(RCUTILS_LOG_SEVERITY_DEBUG, logger, stream_arg)
/**
* \def RCLCPP_DEBUG_STREAM_THROTTLE
* \copydoc RCLCPP_LOG_STREAM_THROTTLE
*/
#define RCLCPP_DEBUG_STREAM_THROTTLE(logger, clock, duration, stream_arg) \
RCLCPP_LOG_STREAM_THROTTLE(RCUTILS_LOG_SEVERITY_DEBUG, logger, clock, duration, stream_arg)
/**
* \def RCLCPP_DEBUG_STREAM_SKIPFIRST_THROTTLE
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE
*/
#define RCLCPP_DEBUG_STREAM_SKIPFIRST_THROTTLE(logger, clock, duration, stream_arg) \
RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_DEBUG, logger, clock, duration, \
stream_arg)
#endif
/** @name Logging macros for severity INFO.
*/
#if (RCLCPP_LOG_MIN_SEVERITY > RCLCPP_LOG_MIN_SEVERITY_INFO)
// empty logging macros for severity INFO when being disabled at compile time
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_INFO(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_INFO_ONCE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_INFO_EXPRESSION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_INFO_FUNCTION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_INFO_SKIPFIRST(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_INFO_THROTTLE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_INFO_SKIPFIRST_THROTTLE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_INFO_STREAM(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_INFO_STREAM_ONCE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_INFO_STREAM_EXPRESSION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_INFO_STREAM_FUNCTION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_INFO_STREAM_SKIPFIRST(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_INFO_STREAM_THROTTLE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_INFO_STREAM_SKIPFIRST_THROTTLE(...)
#else
/**
* \def RCLCPP_INFO
* \copydoc RCLCPP_LOG
*/
#define RCLCPP_INFO(logger, ...) RCLCPP_LOG(RCUTILS_LOG_SEVERITY_INFO, logger, __VA_ARGS__)
/**
* \def RCLCPP_INFO_ONCE
* \copydoc RCLCPP_LOG_ONCE
*/
#define RCLCPP_INFO_ONCE(logger, ...) \
RCLCPP_LOG_ONCE(RCUTILS_LOG_SEVERITY_INFO, logger, __VA_ARGS__)
/**
* \def RCLCPP_INFO_EXPRESSION
* \copydoc RCLCPP_LOG_EXPRESSION
*/
#define RCLCPP_INFO_EXPRESSION(logger, expression, ...) \
RCLCPP_LOG_EXPRESSION(RCUTILS_LOG_SEVERITY_INFO, logger, expression, __VA_ARGS__)
/**
* \def RCLCPP_INFO_FUNCTION
* \copydoc RCLCPP_LOG_FUNCTION
*/
#define RCLCPP_INFO_FUNCTION(logger, function, ...) \
RCLCPP_LOG_FUNCTION(RCUTILS_LOG_SEVERITY_INFO, logger, function, __VA_ARGS__)
/**
* \def RCLCPP_INFO_SKIPFIRST
* \copydoc RCLCPP_LOG_SKIPFIRST
*/
#define RCLCPP_INFO_SKIPFIRST(logger, ...) \
RCLCPP_LOG_SKIPFIRST(RCUTILS_LOG_SEVERITY_INFO, logger, __VA_ARGS__)
/**
* \def RCLCPP_INFO_THROTTLE
* \copydoc RCLCPP_LOG_THROTTLE
*/
#define RCLCPP_INFO_THROTTLE(logger, clock, duration, ...) \
RCLCPP_LOG_THROTTLE(RCUTILS_LOG_SEVERITY_INFO, logger, clock, duration, __VA_ARGS__)
/**
* \def RCLCPP_INFO_SKIPFIRST_THROTTLE
* \copydoc RCLCPP_LOG_SKIPFIRST_THROTTLE
*/
#define RCLCPP_INFO_SKIPFIRST_THROTTLE(logger, clock, duration, ...) \
RCLCPP_LOG_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_INFO, logger, clock, duration, __VA_ARGS__)
/**
* \def RCLCPP_INFO_STREAM
* \copydoc RCLCPP_LOG_STREAM
*/
#define RCLCPP_INFO_STREAM(logger, stream_arg) \
RCLCPP_LOG_STREAM(RCUTILS_LOG_SEVERITY_INFO, logger, stream_arg)
/**
* \def RCLCPP_INFO_STREAM_ONCE
* \copydoc RCLCPP_LOG_STREAM_ONCE
*/
#define RCLCPP_INFO_STREAM_ONCE(logger, stream_arg) \
RCLCPP_LOG_STREAM_ONCE(RCUTILS_LOG_SEVERITY_INFO, logger, stream_arg)
/**
* \def RCLCPP_INFO_STREAM_EXPRESSION
* \copydoc RCLCPP_LOG_STREAM_EXPRESSION
*/
#define RCLCPP_INFO_STREAM_EXPRESSION(logger, expression, stream_arg) \
RCLCPP_LOG_STREAM_EXPRESSION(RCUTILS_LOG_SEVERITY_INFO, logger, expression, stream_arg)
/**
* \def RCLCPP_INFO_STREAM_FUNCTION
* \copydoc RCLCPP_LOG_STREAM_FUNCTION
*/
#define RCLCPP_INFO_STREAM_FUNCTION(logger, function, stream_arg) \
RCLCPP_LOG_STREAM_FUNCTION(RCUTILS_LOG_SEVERITY_INFO, logger, function, stream_args)
/**
* \def RCLCPP_INFO_STREAM_SKIPFIRST
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST
*/
#define RCLCPP_INFO_STREAM_SKIPFIRST(logger, stream_arg) \
RCLCPP_LOG_STREAM_SKIPFIRST(RCUTILS_LOG_SEVERITY_INFO, logger, stream_arg)
/**
* \def RCLCPP_INFO_STREAM_THROTTLE
* \copydoc RCLCPP_LOG_STREAM_THROTTLE
*/
#define RCLCPP_INFO_STREAM_THROTTLE(logger, clock, duration, stream_arg) \
RCLCPP_LOG_STREAM_THROTTLE(RCUTILS_LOG_SEVERITY_INFO, logger, clock, duration, stream_arg)
/**
* \def RCLCPP_INFO_STREAM_SKIPFIRST_THROTTLE
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE
*/
#define RCLCPP_INFO_STREAM_SKIPFIRST_THROTTLE(logger, clock, duration, stream_arg) \
RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_INFO, logger, clock, duration, \
stream_arg)
#endif
/** @name Logging macros for severity WARN.
*/
#if (RCLCPP_LOG_MIN_SEVERITY > RCLCPP_LOG_MIN_SEVERITY_WARN)
// empty logging macros for severity WARN when being disabled at compile time
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_WARN(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_WARN_ONCE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_WARN_EXPRESSION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_WARN_FUNCTION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_WARN_SKIPFIRST(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_WARN_THROTTLE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_WARN_SKIPFIRST_THROTTLE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_WARN_STREAM(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_WARN_STREAM_ONCE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_WARN_STREAM_EXPRESSION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_WARN_STREAM_FUNCTION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_WARN_STREAM_SKIPFIRST(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_WARN_STREAM_THROTTLE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_WARN_STREAM_SKIPFIRST_THROTTLE(...)
#else
/**
* \def RCLCPP_WARN
* \copydoc RCLCPP_LOG
*/
#define RCLCPP_WARN(logger, ...) RCLCPP_LOG(RCUTILS_LOG_SEVERITY_WARN, logger, __VA_ARGS__)
/**
* \def RCLCPP_WARN_ONCE
* \copydoc RCLCPP_LOG_ONCE
*/
#define RCLCPP_WARN_ONCE(logger, ...) \
RCLCPP_LOG_ONCE(RCUTILS_LOG_SEVERITY_WARN, logger, __VA_ARGS__)
/**
* \def RCLCPP_WARN_EXPRESSION
* \copydoc RCLCPP_LOG_EXPRESSION
*/
#define RCLCPP_WARN_EXPRESSION(logger, expression, ...) \
RCLCPP_LOG_EXPRESSION(RCUTILS_LOG_SEVERITY_WARN, logger, expression, __VA_ARGS__)
/**
* \def RCLCPP_WARN_FUNCTION
* \copydoc RCLCPP_LOG_FUNCTION
*/
#define RCLCPP_WARN_FUNCTION(logger, function, ...) \
RCLCPP_LOG_FUNCTION(RCUTILS_LOG_SEVERITY_WARN, logger, function, __VA_ARGS__)
/**
* \def RCLCPP_WARN_SKIPFIRST
* \copydoc RCLCPP_LOG_SKIPFIRST
*/
#define RCLCPP_WARN_SKIPFIRST(logger, ...) \
RCLCPP_LOG_SKIPFIRST(RCUTILS_LOG_SEVERITY_WARN, logger, __VA_ARGS__)
/**
* \def RCLCPP_WARN_THROTTLE
* \copydoc RCLCPP_LOG_THROTTLE
*/
#define RCLCPP_WARN_THROTTLE(logger, clock, duration, ...) \
RCLCPP_LOG_THROTTLE(RCUTILS_LOG_SEVERITY_WARN, logger, clock, duration, __VA_ARGS__)
/**
* \def RCLCPP_WARN_SKIPFIRST_THROTTLE
* \copydoc RCLCPP_LOG_SKIPFIRST_THROTTLE
*/
#define RCLCPP_WARN_SKIPFIRST_THROTTLE(logger, clock, duration, ...) \
RCLCPP_LOG_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_WARN, logger, clock, duration, __VA_ARGS__)
/**
* \def RCLCPP_WARN_STREAM
* \copydoc RCLCPP_LOG_STREAM
*/
#define RCLCPP_WARN_STREAM(logger, stream_arg) \
RCLCPP_LOG_STREAM(RCUTILS_LOG_SEVERITY_WARN, logger, stream_arg)
/**
* \def RCLCPP_WARN_STREAM_ONCE
* \copydoc RCLCPP_LOG_STREAM_ONCE
*/
#define RCLCPP_WARN_STREAM_ONCE(logger, stream_arg) \
RCLCPP_LOG_STREAM_ONCE(RCUTILS_LOG_SEVERITY_WARN, logger, stream_arg)
/**
* \def RCLCPP_WARN_STREAM_EXPRESSION
* \copydoc RCLCPP_LOG_STREAM_EXPRESSION
*/
#define RCLCPP_WARN_STREAM_EXPRESSION(logger, expression, stream_arg) \
RCLCPP_LOG_STREAM_EXPRESSION(RCUTILS_LOG_SEVERITY_WARN, logger, expression, stream_arg)
/**
* \def RCLCPP_WARN_STREAM_FUNCTION
* \copydoc RCLCPP_LOG_STREAM_FUNCTION
*/
#define RCLCPP_WARN_STREAM_FUNCTION(logger, function, stream_arg) \
RCLCPP_LOG_STREAM_FUNCTION(RCUTILS_LOG_SEVERITY_WARN, logger, function, stream_args)
/**
* \def RCLCPP_WARN_STREAM_SKIPFIRST
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST
*/
#define RCLCPP_WARN_STREAM_SKIPFIRST(logger, stream_arg) \
RCLCPP_LOG_STREAM_SKIPFIRST(RCUTILS_LOG_SEVERITY_WARN, logger, stream_arg)
/**
* \def RCLCPP_WARN_STREAM_THROTTLE
* \copydoc RCLCPP_LOG_STREAM_THROTTLE
*/
#define RCLCPP_WARN_STREAM_THROTTLE(logger, clock, duration, stream_arg) \
RCLCPP_LOG_STREAM_THROTTLE(RCUTILS_LOG_SEVERITY_WARN, logger, clock, duration, stream_arg)
/**
* \def RCLCPP_WARN_STREAM_SKIPFIRST_THROTTLE
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE
*/
#define RCLCPP_WARN_STREAM_SKIPFIRST_THROTTLE(logger, clock, duration, stream_arg) \
RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_WARN, logger, clock, duration, \
stream_arg)
#endif
/** @name Logging macros for severity ERROR.
*/
#if (RCLCPP_LOG_MIN_SEVERITY > RCLCPP_LOG_MIN_SEVERITY_ERROR)
// empty logging macros for severity ERROR when being disabled at compile time
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_ERROR(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_ERROR_ONCE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_ERROR_EXPRESSION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_ERROR_FUNCTION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_ERROR_SKIPFIRST(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_ERROR_THROTTLE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_ERROR_SKIPFIRST_THROTTLE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_ERROR_STREAM(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_ERROR_STREAM_ONCE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_ERROR_STREAM_EXPRESSION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_ERROR_STREAM_FUNCTION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_ERROR_STREAM_SKIPFIRST(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_ERROR_STREAM_THROTTLE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_ERROR_STREAM_SKIPFIRST_THROTTLE(...)
#else
/**
* \def RCLCPP_ERROR
* \copydoc RCLCPP_LOG
*/
#define RCLCPP_ERROR(logger, ...) RCLCPP_LOG(RCUTILS_LOG_SEVERITY_ERROR, logger, __VA_ARGS__)
/**
* \def RCLCPP_ERROR_ONCE
* \copydoc RCLCPP_LOG_ONCE
*/
#define RCLCPP_ERROR_ONCE(logger, ...) \
RCLCPP_LOG_ONCE(RCUTILS_LOG_SEVERITY_ERROR, logger, __VA_ARGS__)
/**
* \def RCLCPP_ERROR_EXPRESSION
* \copydoc RCLCPP_LOG_EXPRESSION
*/
#define RCLCPP_ERROR_EXPRESSION(logger, expression, ...) \
RCLCPP_LOG_EXPRESSION(RCUTILS_LOG_SEVERITY_ERROR, logger, expression, __VA_ARGS__)
/**
* \def RCLCPP_ERROR_FUNCTION
* \copydoc RCLCPP_LOG_FUNCTION
*/
#define RCLCPP_ERROR_FUNCTION(logger, function, ...) \
RCLCPP_LOG_FUNCTION(RCUTILS_LOG_SEVERITY_ERROR, logger, function, __VA_ARGS__)
/**
* \def RCLCPP_ERROR_SKIPFIRST
* \copydoc RCLCPP_LOG_SKIPFIRST
*/
#define RCLCPP_ERROR_SKIPFIRST(logger, ...) \
RCLCPP_LOG_SKIPFIRST(RCUTILS_LOG_SEVERITY_ERROR, logger, __VA_ARGS__)
/**
* \def RCLCPP_ERROR_THROTTLE
* \copydoc RCLCPP_LOG_THROTTLE
*/
#define RCLCPP_ERROR_THROTTLE(logger, clock, duration, ...) \
RCLCPP_LOG_THROTTLE(RCUTILS_LOG_SEVERITY_ERROR, logger, clock, duration, __VA_ARGS__)
/**
* \def RCLCPP_ERROR_SKIPFIRST_THROTTLE
* \copydoc RCLCPP_LOG_SKIPFIRST_THROTTLE
*/
#define RCLCPP_ERROR_SKIPFIRST_THROTTLE(logger, clock, duration, ...) \
RCLCPP_LOG_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_ERROR, logger, clock, duration, __VA_ARGS__)
/**
* \def RCLCPP_ERROR_STREAM
* \copydoc RCLCPP_LOG_STREAM
*/
#define RCLCPP_ERROR_STREAM(logger, stream_arg) \
RCLCPP_LOG_STREAM(RCUTILS_LOG_SEVERITY_ERROR, logger, stream_arg)
/**
* \def RCLCPP_ERROR_STREAM_ONCE
* \copydoc RCLCPP_LOG_STREAM_ONCE
*/
#define RCLCPP_ERROR_STREAM_ONCE(logger, stream_arg) \
RCLCPP_LOG_STREAM_ONCE(RCUTILS_LOG_SEVERITY_ERROR, logger, stream_arg)
/**
* \def RCLCPP_ERROR_STREAM_EXPRESSION
* \copydoc RCLCPP_LOG_STREAM_EXPRESSION
*/
#define RCLCPP_ERROR_STREAM_EXPRESSION(logger, expression, stream_arg) \
RCLCPP_LOG_STREAM_EXPRESSION(RCUTILS_LOG_SEVERITY_ERROR, logger, expression, stream_arg)
/**
* \def RCLCPP_ERROR_STREAM_FUNCTION
* \copydoc RCLCPP_LOG_STREAM_FUNCTION
*/
#define RCLCPP_ERROR_STREAM_FUNCTION(logger, function, stream_arg) \
RCLCPP_LOG_STREAM_FUNCTION(RCUTILS_LOG_SEVERITY_ERROR, logger, function, stream_args)
/**
* \def RCLCPP_ERROR_STREAM_SKIPFIRST
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST
*/
#define RCLCPP_ERROR_STREAM_SKIPFIRST(logger, stream_arg) \
RCLCPP_LOG_STREAM_SKIPFIRST(RCUTILS_LOG_SEVERITY_ERROR, logger, stream_arg)
/**
* \def RCLCPP_ERROR_STREAM_THROTTLE
* \copydoc RCLCPP_LOG_STREAM_THROTTLE
*/
#define RCLCPP_ERROR_STREAM_THROTTLE(logger, clock, duration, stream_arg) \
RCLCPP_LOG_STREAM_THROTTLE(RCUTILS_LOG_SEVERITY_ERROR, logger, clock, duration, stream_arg)
/**
* \def RCLCPP_ERROR_STREAM_SKIPFIRST_THROTTLE
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE
*/
#define RCLCPP_ERROR_STREAM_SKIPFIRST_THROTTLE(logger, clock, duration, stream_arg) \
RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_ERROR, logger, clock, duration, \
stream_arg)
#endif
/** @name Logging macros for severity FATAL.
*/
#if (RCLCPP_LOG_MIN_SEVERITY > RCLCPP_LOG_MIN_SEVERITY_FATAL)
// empty logging macros for severity FATAL when being disabled at compile time
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_FATAL(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_FATAL_ONCE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_FATAL_EXPRESSION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_FATAL_FUNCTION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_FATAL_SKIPFIRST(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_FATAL_THROTTLE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_FATAL_SKIPFIRST_THROTTLE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_FATAL_STREAM(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_FATAL_STREAM_ONCE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_FATAL_STREAM_EXPRESSION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_FATAL_STREAM_FUNCTION(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_FATAL_STREAM_SKIPFIRST(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_FATAL_STREAM_THROTTLE(...)
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_FATAL_STREAM_SKIPFIRST_THROTTLE(...)
#else
/**
* \def RCLCPP_FATAL
* \copydoc RCLCPP_LOG
*/
#define RCLCPP_FATAL(logger, ...) RCLCPP_LOG(RCUTILS_LOG_SEVERITY_FATAL, logger, __VA_ARGS__)
/**
* \def RCLCPP_FATAL_ONCE
* \copydoc RCLCPP_LOG_ONCE
*/
#define RCLCPP_FATAL_ONCE(logger, ...) \
RCLCPP_LOG_ONCE(RCUTILS_LOG_SEVERITY_FATAL, logger, __VA_ARGS__)
/**
* \def RCLCPP_FATAL_EXPRESSION
* \copydoc RCLCPP_LOG_EXPRESSION
*/
#define RCLCPP_FATAL_EXPRESSION(logger, expression, ...) \
RCLCPP_LOG_EXPRESSION(RCUTILS_LOG_SEVERITY_FATAL, logger, expression, __VA_ARGS__)
/**
* \def RCLCPP_FATAL_FUNCTION
* \copydoc RCLCPP_LOG_FUNCTION
*/
#define RCLCPP_FATAL_FUNCTION(logger, function, ...) \
RCLCPP_LOG_FUNCTION(RCUTILS_LOG_SEVERITY_FATAL, logger, function, __VA_ARGS__)
/**
* \def RCLCPP_FATAL_SKIPFIRST
* \copydoc RCLCPP_LOG_SKIPFIRST
*/
#define RCLCPP_FATAL_SKIPFIRST(logger, ...) \
RCLCPP_LOG_SKIPFIRST(RCUTILS_LOG_SEVERITY_FATAL, logger, __VA_ARGS__)
/**
* \def RCLCPP_FATAL_THROTTLE
* \copydoc RCLCPP_LOG_THROTTLE
*/
#define RCLCPP_FATAL_THROTTLE(logger, clock, duration, ...) \
RCLCPP_LOG_THROTTLE(RCUTILS_LOG_SEVERITY_FATAL, logger, clock, duration, __VA_ARGS__)
/**
* \def RCLCPP_FATAL_SKIPFIRST_THROTTLE
* \copydoc RCLCPP_LOG_SKIPFIRST_THROTTLE
*/
#define RCLCPP_FATAL_SKIPFIRST_THROTTLE(logger, clock, duration, ...) \
RCLCPP_LOG_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_FATAL, logger, clock, duration, __VA_ARGS__)
/**
* \def RCLCPP_FATAL_STREAM
* \copydoc RCLCPP_LOG_STREAM
*/
#define RCLCPP_FATAL_STREAM(logger, stream_arg) \
RCLCPP_LOG_STREAM(RCUTILS_LOG_SEVERITY_FATAL, logger, stream_arg)
/**
* \def RCLCPP_FATAL_STREAM_ONCE
* \copydoc RCLCPP_LOG_STREAM_ONCE
*/
#define RCLCPP_FATAL_STREAM_ONCE(logger, stream_arg) \
RCLCPP_LOG_STREAM_ONCE(RCUTILS_LOG_SEVERITY_FATAL, logger, stream_arg)
/**
* \def RCLCPP_FATAL_STREAM_EXPRESSION
* \copydoc RCLCPP_LOG_STREAM_EXPRESSION
*/
#define RCLCPP_FATAL_STREAM_EXPRESSION(logger, expression, stream_arg) \
RCLCPP_LOG_STREAM_EXPRESSION(RCUTILS_LOG_SEVERITY_FATAL, logger, expression, stream_arg)
/**
* \def RCLCPP_FATAL_STREAM_FUNCTION
* \copydoc RCLCPP_LOG_STREAM_FUNCTION
*/
#define RCLCPP_FATAL_STREAM_FUNCTION(logger, function, stream_arg) \
RCLCPP_LOG_STREAM_FUNCTION(RCUTILS_LOG_SEVERITY_FATAL, logger, function, stream_args)
/**
* \def RCLCPP_FATAL_STREAM_SKIPFIRST
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST
*/
#define RCLCPP_FATAL_STREAM_SKIPFIRST(logger, stream_arg) \
RCLCPP_LOG_STREAM_SKIPFIRST(RCUTILS_LOG_SEVERITY_FATAL, logger, stream_arg)
/**
* \def RCLCPP_FATAL_STREAM_THROTTLE
* \copydoc RCLCPP_LOG_STREAM_THROTTLE
*/
#define RCLCPP_FATAL_STREAM_THROTTLE(logger, clock, duration, stream_arg) \
RCLCPP_LOG_STREAM_THROTTLE(RCUTILS_LOG_SEVERITY_FATAL, logger, clock, duration, stream_arg)
/**
* \def RCLCPP_FATAL_STREAM_SKIPFIRST_THROTTLE
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE
*/
#define RCLCPP_FATAL_STREAM_SKIPFIRST_THROTTLE(logger, clock, duration, stream_arg) \
RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_FATAL, logger, clock, duration, \
stream_arg)
#endif
#endif // RCLCPP__LOGGING_HPP_

View File

@@ -64,9 +64,11 @@ public:
virtual void clear_handles() = 0;
virtual void remove_null_handles(rcl_wait_set_t * wait_set) = 0;
virtual void add_guard_condition(const rcl_guard_condition_t * guard_condition) = 0;
virtual void
add_guard_condition(const rclcpp::GuardCondition & guard_condition) = 0;
virtual void remove_guard_condition(const rcl_guard_condition_t * guard_condition) = 0;
virtual void
remove_guard_condition(const rclcpp::GuardCondition * guard_condition) = 0;
virtual void
get_next_subscription(
@@ -98,52 +100,52 @@ public:
static rclcpp::SubscriptionBase::SharedPtr
get_subscription_by_handle(
std::shared_ptr<const rcl_subscription_t> subscriber_handle,
const std::shared_ptr<const rcl_subscription_t> & subscriber_handle,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
static rclcpp::ServiceBase::SharedPtr
get_service_by_handle(
std::shared_ptr<const rcl_service_t> service_handle,
const std::shared_ptr<const rcl_service_t> & service_handle,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
static rclcpp::ClientBase::SharedPtr
get_client_by_handle(
std::shared_ptr<const rcl_client_t> client_handle,
const std::shared_ptr<const rcl_client_t> & client_handle,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
static rclcpp::TimerBase::SharedPtr
get_timer_by_handle(
std::shared_ptr<const rcl_timer_t> timer_handle,
const std::shared_ptr<const rcl_timer_t> & timer_handle,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
static rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
get_node_by_group(
rclcpp::CallbackGroup::SharedPtr group,
const rclcpp::CallbackGroup::SharedPtr & group,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
static rclcpp::CallbackGroup::SharedPtr
get_group_by_subscription(
rclcpp::SubscriptionBase::SharedPtr subscription,
const rclcpp::SubscriptionBase::SharedPtr & subscription,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
static rclcpp::CallbackGroup::SharedPtr
get_group_by_service(
rclcpp::ServiceBase::SharedPtr service,
const rclcpp::ServiceBase::SharedPtr & service,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
static rclcpp::CallbackGroup::SharedPtr
get_group_by_client(
rclcpp::ClientBase::SharedPtr client,
const rclcpp::ClientBase::SharedPtr & client,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
static rclcpp::CallbackGroup::SharedPtr
get_group_by_timer(
rclcpp::TimerBase::SharedPtr timer,
const rclcpp::TimerBase::SharedPtr & timer,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
static rclcpp::CallbackGroup::SharedPtr
get_group_by_waitable(
rclcpp::Waitable::SharedPtr waitable,
const rclcpp::Waitable::SharedPtr & waitable,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
};

View File

@@ -18,6 +18,7 @@
#include <memory>
#include <stdexcept>
#include "rcl/allocator.h"
#include "rcl/types.h"
#include "rclcpp/allocator/allocator_common.hpp"
@@ -61,7 +62,16 @@ public:
message_allocator_ = std::make_shared<MessageAlloc>();
serialized_message_allocator_ = std::make_shared<SerializedMessageAlloc>();
buffer_allocator_ = std::make_shared<BufferAlloc>();
rcutils_allocator_ = allocator::get_rcl_allocator<char, BufferAlloc>(*buffer_allocator_.get());
if constexpr (std::is_same_v<Alloc, std::allocator<void>>) {
rcutils_allocator_ = rcl_get_default_allocator();
} else {
if constexpr (rclcpp::allocator::has_get_rcl_allocator_v<Alloc>) {
rcutils_allocator_ = message_allocator_->get_rcl_allocator();
} else {
rcutils_allocator_ = allocator::get_rcl_allocator<char,
BufferAlloc>(*buffer_allocator_.get());
}
}
}
explicit MessageMemoryStrategy(std::shared_ptr<Alloc> allocator)
@@ -69,7 +79,16 @@ public:
message_allocator_ = std::make_shared<MessageAlloc>(*allocator.get());
serialized_message_allocator_ = std::make_shared<SerializedMessageAlloc>(*allocator.get());
buffer_allocator_ = std::make_shared<BufferAlloc>(*allocator.get());
rcutils_allocator_ = allocator::get_rcl_allocator<char, BufferAlloc>(*buffer_allocator_.get());
if constexpr (std::is_same_v<Alloc, std::allocator<void>>) {
rcutils_allocator_ = rcl_get_default_allocator();
} else {
if constexpr (rclcpp::allocator::has_get_rcl_allocator_v<Alloc>) {
rcutils_allocator_ = allocator->get_rcl_allocator();
} else {
rcutils_allocator_ = allocator::get_rcl_allocator<char,
BufferAlloc>(*buffer_allocator_.get());
}
}
}
virtual ~MessageMemoryStrategy() = default;

View File

@@ -42,7 +42,9 @@
#include "rclcpp/clock.hpp"
#include "rclcpp/context.hpp"
#include "rclcpp/event.hpp"
#include "rclcpp/generic_client.hpp"
#include "rclcpp/generic_publisher.hpp"
#include "rclcpp/generic_service.hpp"
#include "rclcpp/generic_subscription.hpp"
#include "rclcpp/logger.hpp"
#include "rclcpp/macros.hpp"
@@ -56,6 +58,7 @@
#include "rclcpp/node_interfaces/node_time_source_interface.hpp"
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/node_interfaces/node_type_descriptions_interface.hpp"
#include "rclcpp/node_interfaces/node_waitables_interface.hpp"
#include "rclcpp/node_options.hpp"
#include "rclcpp/parameter.hpp"
@@ -227,38 +230,53 @@ public:
)
);
/// Create a timer.
/// Create a wall timer that uses the wall clock to drive the callback.
/**
* \param[in] period Time interval between triggers of the callback.
* \param[in] callback User-defined callback function.
* \param[in] group Callback group to execute this timer's callback in.
* \param[in] autostart The state of the clock on initialization.
*/
template<typename DurationRepT = int64_t, typename DurationT = std::milli, typename CallbackT>
typename rclcpp::WallTimer<CallbackT>::SharedPtr
create_wall_timer(
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
const rclcpp::CallbackGroup::SharedPtr & group = nullptr,
bool autostart = true);
/// Create a timer that uses the node clock to drive the callback.
/**
* \param[in] period Time interval between triggers of the callback.
* \param[in] callback User-defined callback function.
* \param[in] group Callback group to execute this timer's callback in.
*/
template<typename DurationRepT = int64_t, typename DurationT = std::milli, typename CallbackT>
typename rclcpp::GenericTimer<CallbackT>::SharedPtr
create_timer(
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
const rclcpp::CallbackGroup::SharedPtr & group = nullptr);
/// Create and return a Client.
/**
* \param[in] service_name The topic to service on.
* \param[in] qos_profile rmw_qos_profile_t Quality of service profile for client.
* \param[in] group Callback group to call the service.
* \param[in] service_name The name on which the service is accessible.
* \param[in] qos Quality of service profile for client.
* \param[in] group Callback group to handle the reply to service calls.
* \return Shared pointer to the created client.
*/
template<typename ServiceT>
typename rclcpp::Client<ServiceT>::SharedPtr
create_client(
const std::string & service_name,
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
const rclcpp::CallbackGroup::SharedPtr & group = nullptr);
/// Create and return a Service.
/**
* \param[in] service_name The topic to service on.
* \param[in] callback User-defined callback function.
* \param[in] qos_profile rmw_qos_profile_t Quality of service profile for client.
* \param[in] qos Quality of service profile for the service.
* \param[in] group Callback group to call the service.
* \return Shared pointer to the created service.
*/
@@ -267,8 +285,42 @@ public:
create_service(
const std::string & service_name,
CallbackT && callback,
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
const rclcpp::CallbackGroup::SharedPtr & group = nullptr);
/// Create and return a GenericClient.
/**
* \param[in] service_name The name on which the service is accessible.
* \param[in] service_type The name of service type, e.g. "std_srvs/srv/SetBool"
* \param[in] qos Quality of service profile for client.
* \param[in] group Callback group to handle the reply to service calls.
* \return Shared pointer to the created GenericClient.
*/
RCLCPP_PUBLIC
rclcpp::GenericClient::SharedPtr
create_generic_client(
const std::string & service_name,
const std::string & service_type,
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
const rclcpp::CallbackGroup::SharedPtr & group = nullptr);
/// Create and return a GenericService.
/**
* \param[in] service_name The topic to service on.
* \param[in] service_type The name of service type, e.g. "std_srvs/srv/SetBool"
* \param[in] callback User-defined callback function.
* \param[in] qos Quality of service profile for the service.
* \param[in] group Callback group to call the service.
* \return Shared pointer to the created service.
*/
template<typename CallbackT>
typename rclcpp::GenericService::SharedPtr
create_generic_service(
const std::string & service_name,
const std::string & service_type,
CallbackT && callback,
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
const rclcpp::CallbackGroup::SharedPtr & group = nullptr);
/// Create and return a GenericPublisher.
/**
@@ -308,12 +360,14 @@ public:
* `%callback_group`.
* \return Shared pointer to the created generic subscription.
*/
template<typename AllocatorT = std::allocator<void>>
template<
typename CallbackT,
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,
CallbackT && callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
)
@@ -336,11 +390,21 @@ public:
*
* If `ignore_override` is `true`, the parameter override will be ignored.
*
* This method, if successful, will result in any callback registered with
* add_on_set_parameters_callback to be called.
* This method will result in any callback registered with
* `add_on_set_parameters_callback` and `add_post_set_parameters_callback`
* to be called for the parameter being set.
*
* If a callback was registered previously with `add_on_set_parameters_callback`,
* it will be called prior to setting the parameter for the node.
* If that callback prevents the initial value for the parameter from being
* set then rclcpp::exceptions::InvalidParameterValueException is thrown.
*
* If a callback was registered previously with `add_post_set_parameters_callback`,
* it will be called after setting the parameter successfully for the node.
*
* This method will _not_ result in any callbacks registered with
* `add_pre_set_parameters_callback` to be called.
*
* The returned reference will remain valid until the parameter is
* undeclared.
*
@@ -395,22 +459,6 @@ public:
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.
@@ -473,11 +521,22 @@ public:
* If `ignore_overrides` is `true`, all the overrides of the parameters declared
* by the function call will be ignored.
*
* This method will result in any callback registered with
* `add_on_set_parameters_callback` and `add_post_set_parameters_callback`
* to be called once for each parameter.
*
* This method, if successful, will result in any callback registered with
* add_on_set_parameters_callback to be called, once for each parameter.
* `add_on_set_parameters_callback` to be called, once for each parameter.
* If that callback prevents the initial value for any parameter from being
* set then rclcpp::exceptions::InvalidParameterValueException is thrown.
*
* If a callback was registered previously with `add_post_set_parameters_callback`,
* it will be called after setting the parameters successfully for the node,
* once for each parameter.
*
* This method will _not_ result in any callbacks registered with
* `add_pre_set_parameters_callback` to be called.
*
* \param[in] namespace_ The namespace in which to declare the parameters.
* \param[in] parameters The parameters to set in the given namespace.
* \param[in] ignore_overrides When `true`, the parameters overrides are ignored.
@@ -515,8 +574,9 @@ public:
/// Undeclare a previously declared parameter.
/**
* This method will not cause a callback registered with
* add_on_set_parameters_callback to be called.
* This method will _not_ cause a callback registered with any of the
* `add_pre_set_parameters_callback`, `add_on_set_parameters_callback` and
* `add_post_set_parameters_callback` to be called.
*
* \param[in] name The name of the parameter to be undeclared.
* \throws rclcpp::exceptions::ParameterNotDeclaredException if the parameter
@@ -550,11 +610,24 @@ public:
* Parameter overrides are ignored by set_parameter.
*
* This method will result in any callback registered with
* add_on_set_parameters_callback to be called.
* `add_pre_set_parameters_callback`, add_on_set_parameters_callback` and
* `add_post_set_parameters_callback` to be called once for the parameter
* being set.
*
* This method will result in any callback registered with
* `add_on_set_parameters_callback` to be called.
* If the callback prevents the parameter from being set, then it will be
* reflected in the SetParametersResult that is returned, but no exception
* will be thrown.
*
* If a callback was registered previously with `add_pre_set_parameters_callback`,
* it will be called once prior to the validation of the parameter for the node.
* If this callback makes modified parameter list empty, then it will be reflected
* in the returned result; no exceptions will be raised in this case.
*
* If a callback was registered previously with `add_post_set_parameters_callback`,
* it will be called once after setting the parameter successfully for the node.
*
* If the value type of the parameter is rclcpp::PARAMETER_NOT_SET, and the
* existing parameter type is something else, then the parameter will be
* implicitly undeclared.
@@ -591,11 +664,25 @@ public:
* corresponding SetParametersResult in the vector returned by this function.
*
* This method will result in any callback registered with
* add_on_set_parameters_callback to be called, once for each parameter.
* `add_pre_set_parameters_callback`, `add_on_set_parameters_callback` and
* `add_post_set_parameters_callback` to be called once for each parameter.
* If a callback was registered previously with `add_pre_set_parameters_callback`,
* it will be called prior to the validation of parameters for the node,
* once for each parameter.
* If this callback makes modified parameter list empty, then it will be reflected
* in the returned result; no exceptions will be raised in this case.
*
* This method will result in any callback registered with
* `add_on_set_parameters_callback` to be called, once for each parameter.
* If the callback prevents the parameter from being set, then, as mentioned
* before, it will be reflected in the corresponding SetParametersResult
* that is returned, but no exception will be thrown.
*
* If a callback was registered previously with `add_post_set_parameters_callback`,
* it will be called after setting the parameters successfully for the node,
* once for each parameter.
*
* Like set_parameter() this method will implicitly undeclare parameters
* with the type rclcpp::PARAMETER_NOT_SET.
*
@@ -622,11 +709,25 @@ public:
* If the exception is thrown then none of the parameters will have been set.
*
* This method will result in any callback registered with
* add_on_set_parameters_callback to be called, just one time.
* `add_pre_set_parameters_callback`, `add_on_set_parameters_callback` and
* `add_post_set_parameters_callback` to be called only 'once' for all parameters.
*
* If a callback was registered previously with `add_pre_set_parameters_callback`,
* it will be called prior to the validation of node parameters, just one time
* for all parameters.
* If this callback makes modified parameter list empty, then it will be reflected
* in the returned result; no exceptions will be raised in this case.
*
* This method will result in any callback registered with
* 'add_on_set_parameters_callback' to be called, just one time.
* If the callback prevents the parameters from being set, then it will be
* reflected in the SetParametersResult which is returned, but no exception
* will be thrown.
*
* If a callback was registered previously with `add_post_set_parameters_callback`,
* it will be called after setting the node parameters successfully, just one time
* for all parameters.
*
* If you pass multiple rclcpp::Parameter instances with the same name, then
* only the last one in the vector (forward iteration) will be set.
*
@@ -646,17 +747,21 @@ public:
/**
* If the parameter has not been declared, then this method may throw the
* rclcpp::exceptions::ParameterNotDeclaredException exception.
* If the parameter has not been initialized, then this method may throw the
* rclcpp::exceptions::ParameterUninitializedException exception.
*
* If undeclared parameters are allowed, see the node option
* rclcpp::NodeOptions::allow_undeclared_parameters, then this method will
* not throw an exception, and instead return a default initialized
* rclcpp::Parameter, which has a type of
* not throw the rclcpp::exceptions::ParameterNotDeclaredException exception,
* and instead return a default initialized rclcpp::Parameter, which has a type of
* rclcpp::ParameterType::PARAMETER_NOT_SET.
*
* \param[in] name The name of the parameter to get.
* \return The requested parameter inside of a rclcpp parameter object.
* \throws rclcpp::exceptions::ParameterNotDeclaredException if the parameter
* has not been declared and undeclared parameters are not allowed.
* \throws rclcpp::exceptions::ParameterUninitializedException if the parameter
* has not been initialized.
*/
RCLCPP_PUBLIC
rclcpp::Parameter
@@ -720,14 +825,32 @@ public:
ParameterT & parameter,
const ParameterT & alternative_value) const;
/// Return the parameter value, or the "alternative_value" if not set.
/**
* If the parameter was not set, then the "alternative_value" argument is returned.
*
* This method will not throw the rclcpp::exceptions::ParameterNotDeclaredException exception.
*
* In all cases, the parameter is never set or declared within the node.
*
* \param[in] name The name of the parameter to get.
* \param[in] alternative_value Value to be stored in output if the parameter was not set.
* \returns The value of the parameter.
*/
template<typename ParameterT>
ParameterT
get_parameter_or(
const std::string & name,
const ParameterT & alternative_value) const;
/// Return the parameters by the given parameter names.
/**
* Like get_parameters(), this method may throw the
* Like get_parameter(const std::string &), this method may throw the
* rclcpp::exceptions::ParameterNotDeclaredException exception if the
* requested parameter has not been declared and undeclared parameters are
* not allowed.
* not allowed, and may throw the rclcpp::exceptions::ParameterUninitializedException exception.
*
* Also like get_parameters(), if undeclared parameters are allowed and the
* Also like get_parameter(const std::string &), if undeclared parameters are allowed and the
* parameter has not been declared, then the corresponding rclcpp::Parameter
* will be default initialized and therefore have the type
* rclcpp::ParameterType::PARAMETER_NOT_SET.
@@ -737,6 +860,8 @@ public:
* \throws rclcpp::exceptions::ParameterNotDeclaredException if any of the
* parameters have not been declared and undeclared parameters are not
* allowed.
* \throws rclcpp::exceptions::ParameterUninitializedException if any of the
* parameters have not been initialized.
*/
RCLCPP_PUBLIC
std::vector<rclcpp::Parameter>
@@ -851,18 +976,98 @@ public:
/// Return a list of parameters with any of the given prefixes, up to the given depth.
/**
* \todo: properly document and test this method.
* Parameters are separated into a hierarchy using the "." (dot) character.
* The "prefixes" argument is a way to select only particular parts of the hierarchy.
*
* \param[in] prefixes The list of prefixes that should be searched for within the
* current parameters. If this vector of prefixes is empty, then list_parameters
* will return all parameters.
* \param[in] depth An unsigned integer that represents the recursive depth to search.
* If this depth = 0, then all parameters that fit the prefixes will be returned.
* \returns A ListParametersResult message which contains both an array of unique prefixes
* and an array of names that were matched to the prefixes given.
*/
RCLCPP_PUBLIC
rcl_interfaces::msg::ListParametersResult
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const;
using PreSetParametersCallbackHandle =
rclcpp::node_interfaces::PreSetParametersCallbackHandle;
using PreSetParametersCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::PreSetParametersCallbackType;
using OnSetParametersCallbackHandle =
rclcpp::node_interfaces::OnSetParametersCallbackHandle;
using OnParametersSetCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::OnParametersSetCallbackType;
using OnSetParametersCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::OnSetParametersCallbackType;
/// Add a callback for when parameters are being set.
using PostSetParametersCallbackHandle =
rclcpp::node_interfaces::PostSetParametersCallbackHandle;
using PostSetParametersCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::PostSetParametersCallbackType;
/// Add a callback that gets triggered before parameters are validated.
/**
* This callback can be used to modify the original list of parameters being
* set by the user.
*
* The modified list of parameters is then forwarded to the "on set parameter"
* callback for validation.
*
* The callback is called whenever any of the `set_parameter*` methods are called
* or when a set parameter service request is received.
*
* The callback takes a reference to the vector of parameters to be set.
*
* The vector of parameters may be modified by the callback.
*
* One of the use case of "pre set callback" can be updating additional parameters
* conditioned on changes to a parameter.
*
* Users should retain a copy of the returned shared pointer, as the callback
* is valid only as long as the smart pointer is alive.
*
* For an example callback:
*
*```cpp
* void
* preSetParameterCallback(std::vector<rclcpp::Parameter> & parameters)
* {
* for (auto & param : parameters) {
* if (param.get_name() == "param1") {
* parameters.push_back(rclcpp::Parameter("param2", 4.0));
* }
* }
* }
* ```
* The above callback appends 'param2' to the list of parameters to be set if
* 'param1' is being set by the user.
*
* All parameters in the vector will be set atomically.
*
* Note that the callback is only called while setting parameters with `set_parameter`,
* `set_parameters`, `set_parameters_atomically`, or externally with a parameters service.
*
* The callback is not called when parameters are declared with `declare_parameter`
* or `declare_parameters`.
*
* The callback is not called when parameters are undeclared with `undeclare_parameter`.
*
* An empty modified parameter list from the callback will result in "set_parameter*"
* returning an unsuccessful result.
*
* The `remove_pre_set_parameters_callback` can be used to deregister the callback.
*
* \param callback The callback to register.
* \returns A shared pointer. The callback is valid as long as the smart pointer is alive.
* \throws std::bad_alloc if the allocation of the PreSetParametersCallbackHandle fails.
*/
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
PreSetParametersCallbackHandle::SharedPtr
add_pre_set_parameters_callback(PreSetParametersCallbackType callback);
/// Add a callback to validate parameters before they are set.
/**
* The callback signature is designed to allow handling of any of the above
* `set_parameter*` or `declare_parameter*` methods, and so it takes a const
@@ -870,6 +1075,9 @@ public:
* rcl_interfaces::msg::SetParametersResult to indicate whether or not the
* parameter should be set or not, and if not why.
*
* Users should retain a copy of the returned shared pointer, as the callback
* is valid only as long as the smart pointer is alive.
*
* For an example callback:
*
* ```cpp
@@ -901,6 +1109,8 @@ public:
* this callback, so when checking a new value against the existing one, you
* must account for the case where the parameter is not yet set.
*
* The callback is not called when parameters are undeclared with `undeclare_parameter`.
*
* Some constraints like read_only are enforced before the callback is called.
*
* The callback may introspect other already set parameters (by calling any
@@ -929,7 +1139,80 @@ public:
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
OnSetParametersCallbackHandle::SharedPtr
add_on_set_parameters_callback(OnParametersSetCallbackType callback);
add_on_set_parameters_callback(OnSetParametersCallbackType callback);
/// Add a callback that gets triggered after parameters are set successfully.
/**
* The callback is called when any of the `set_parameter*` or `declare_parameter*`
* methods are successful.
*
* Users should retain a copy of the returned shared pointer, as the callback
* is valid only as long as the smart pointer is alive.
*
* The callback takes a reference to a const vector of parameters that have been
* set successfully.
*
* The post callback can be valuable as a place to cause side-effects based on
* parameter changes.
* For instance updating internally tracked class attributes once parameters
* have been changed successfully.
*
* For an example callback:
*
* ```cpp
* void
* postSetParameterCallback(const std::vector<rclcpp::Parameter> & parameters)
* {
* for(const auto & param:parameters) {
* // the internal class member can be changed after
* // successful change to param1 or param2
* if(param.get_name() == "param1") {
* internal_tracked_class_parameter_1_ = param.get_value<double>();
* }
* else if(param.get_name() == "param2") {
* internal_tracked_class_parameter_2_ = param.get_value<double>();
* }
* }
* }
* ```
*
* The above callback takes a const reference to list of parameters that have been
* set successfully and as a result of this updates the internally tracked class attributes
* `internal_tracked_class_parameter_1_` and `internal_tracked_class_parameter_2_`
* respectively.
*
* This callback should not modify parameters.
*
* The callback is called when parameters are declared with `declare_parameter`
* or `declare_parameters`. See `declare_parameter` or `declare_parameters` above.
*
* The callback is not called when parameters are undeclared with `undeclare_parameter`.
*
* If you want to make changes to parameters based on changes to another, use
* `add_pre_set_parameters_callback`.
*
* The `remove_post_set_parameters_callback` can be used to deregister the callback.
*
* \param callback The callback to register.
* \returns A shared pointer. The callback is valid as long as the smart pointer is alive.
* \throws std::bad_alloc if the allocation of the OnSetParametersCallbackHandle fails.
*/
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
PostSetParametersCallbackHandle::SharedPtr
add_post_set_parameters_callback(PostSetParametersCallbackType callback);
/// Remove a callback registered with `add_pre_set_parameters_callback`.
/**
* Delete a handler returned by `add_pre_set_parameters_callback`.
*
* \param handler The callback handler to remove.
* \throws std::runtime_error if the handler was not created with `add_pre_set_parameters_callback`,
* or if it has been removed before.
*/
RCLCPP_PUBLIC
void
remove_pre_set_parameters_callback(const PreSetParametersCallbackHandle * const handler);
/// Remove a callback registered with `add_on_set_parameters_callback`.
/**
@@ -958,6 +1241,18 @@ public:
void
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler);
/// Remove a callback registered with `add_post_set_parameters_callback`.
/**
* Delete a handler returned by `add_post_set_parameters_callback`.
*
* \param handler The callback handler to remove.
* \throws std::runtime_error if the handler was not created with `add_post_set_parameters_callback`,
* or if it has been removed before.
*/
RCLCPP_PUBLIC
void
remove_post_set_parameters_callback(const PostSetParametersCallbackHandle * const handler);
/// Get the fully-qualified names of all available nodes.
/**
* The fully-qualified name includes the local namespace and name of the node.
@@ -1021,6 +1316,26 @@ public:
size_t
count_subscribers(const std::string & topic_name) const;
/// Return the number of clients created for a given service.
/**
* \param[in] service_name the actual service name used; it will not be automatically remapped.
* \return number of clients that have been created for the given service.
* \throws std::runtime_error if clients could not be counted
*/
RCLCPP_PUBLIC
size_t
count_clients(const std::string & service_name) const;
/// Return the number of services created for a given service.
/**
* \param[in] service_name the actual service name used; it will not be automatically remapped.
* \return number of services that have been created for the given service.
* \throws std::runtime_error if services could not be counted
*/
RCLCPP_PUBLIC
size_t
count_services(const std::string & service_name) const;
/// Return the topic endpoint information about publishers on a given topic.
/**
* The returned parameter is a list of topic endpoint information, where each item will contain
@@ -1073,6 +1388,66 @@ public:
std::vector<rclcpp::TopicEndpointInfo>
get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle = false) const;
/// Return the service endpoint information about clients on a given service.
/**
* The returned parameter is a list of service endpoint information, where each item will contain
* the node name, node namespace, service type, endpoint type, endpoint count,
* service endpoint's GIDs, and its QoS profiles.
*
* When the `no_mangle` parameter is `true`, the provided `service_name` should be a valid service
* name for the middleware (useful when combining ROS with native middleware apps).
* When the `no_mangle` parameter is `false`, the provided `service_name` should follow
* ROS service name conventions. In DDS-based RMWs, services are implemented as topics with mangled
* names (e.g., `rq/my_serviceRequest` and `rp/my_serviceReply`), so `no_mangle = true` is not
* supported and will result in an error. Use `get_publishers_info_by_topic` or
* `get_subscriptions_info_by_topic` for unmangled topic queries in such cases. Other RMWs
* (e.g., Zenoh) may support `no_mangle = true` if they natively handle services without topic-based
*
* 'service_name` may be a relative, private, or fully qualified service name.
* A relative or private service will be expanded using this node's namespace and name.
* The queried `service_name` is not remapped.
*
* \param[in] service_name the actual service name used; it will not be automatically remapped.
* \param[in] no_mangle if `true`, `service_name` needs to be a valid middleware service name,
* otherwise it should be a valid ROS service name. Defaults to `false`.
* \return a list of SeviceEndpointInfo representing all the clients on this service.
* \throws InvalidServiceNameError if the given service_name is invalid.
* \throws std::runtime_error if internal error happens.
*/
RCLCPP_PUBLIC
std::vector<rclcpp::ServiceEndpointInfo>
get_clients_info_by_service(const std::string & service_name, bool no_mangle = false) const;
/// Return the service endpoint information about servers on a given service.
/**
* The returned parameter is a list of service endpoint information, where each item will contain
* the node name, node namespace, service type, endpoint type, endpoint count,
* service endpoint's GIDs, and its QoS profiles.
*
* When the `no_mangle` parameter is `true`, the provided `service_name` should be a valid service
* name for the middleware (useful when combining ROS with native middleware apps).
* When the `no_mangle` parameter is `false`, the provided `service_name` should follow
* ROS service name conventions. In DDS-based RMWs, services are implemented as topics with mangled
* names (e.g., `rq/my_serviceRequest` and `rp/my_serviceReply`), so `no_mangle = true` is not
* supported and will result in an error. Use `rcl_get_publishers_info_by_topic` or
* `rcl_get_subscriptions_info_by_topic` for unmangled topic queries in such cases. Other RMWs
* (e.g., Zenoh) may support `no_mangle = true` if they natively handle services without topic-based
*
* 'service_name` may be a relative, private, or fully qualified service name.
* A relative or private service will be expanded using this node's namespace and name.
* The queried `service_name` is not remapped.
*
* \param[in] service_name the actual service name used; it will not be automatically remapped.
* \param[in] no_mangle if `true`, `service_name` needs to be a valid middleware service name,
* otherwise it should be a valid ROS service name. Defaults to `false`.
* \return a list of SeviceEndpointInfo representing all the servers on this service.
* \throws InvalidServiceNameError if the given service_name is invalid.
* \throws std::runtime_error if internal error happens.
*/
RCLCPP_PUBLIC
std::vector<rclcpp::ServiceEndpointInfo>
get_servers_info_by_service(const std::string & service_name, bool no_mangle = false) const;
/// Return a graph event, which will be set anytime a graph change occurs.
/* The graph Event object is a loan which must be returned.
* The Event object is scoped and therefore to return the loan just let it go
@@ -1096,7 +1471,7 @@ public:
RCLCPP_PUBLIC
void
wait_for_graph_change(
rclcpp::Event::SharedPtr event,
const rclcpp::Event::SharedPtr & event,
std::chrono::nanoseconds timeout);
/// Get a clock as a non-const shared pointer which is managed by the node.
@@ -1115,7 +1490,7 @@ public:
rclcpp::Clock::ConstSharedPtr
get_clock() const;
/// Returns current time from the time source specified by clock_type.
/// Returns current time from the node clock.
/**
* \sa rclcpp::Clock::now
*/
@@ -1173,6 +1548,11 @@ public:
rclcpp::node_interfaces::NodeTimeSourceInterface::SharedPtr
get_node_time_source_interface();
/// Return the Node's internal NodeTypeDescriptionsInterface implementation.
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr
get_node_type_descriptions_interface();
/// Return the sub-namespace, if this is a sub-node, otherwise an empty string.
/**
* The returned sub-namespace is either the accumulated sub-namespaces which
@@ -1239,6 +1619,10 @@ public:
* which has been created using an existing instance of this class, but which
* has an additional sub-namespace (short for subordinate namespace)
* associated with it.
* A subordinate node and an instance of this class share all the node interfaces
* such as `rclcpp::node_interfaces::NodeParametersInterface`.
* Subordinate nodes are primarily used to organize namespaces and provide a
* hierarchical structure, but they are not meant to be completely independent nodes.
* The sub-namespace will extend the node's namespace for the purpose of
* creating additional entities, such as Publishers, Subscriptions, Service
* Clients and Servers, and so on.
@@ -1305,11 +1689,18 @@ private:
rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock_;
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters_;
rclcpp::node_interfaces::NodeTimeSourceInterface::SharedPtr node_time_source_;
rclcpp::node_interfaces::NodeTypeDescriptionsInterface::SharedPtr node_type_descriptions_;
rclcpp::node_interfaces::NodeWaitablesInterface::SharedPtr node_waitables_;
const rclcpp::NodeOptions node_options_;
const std::string sub_namespace_;
const std::string effective_namespace_;
class NodeImpl;
// This member is meant to be a place to backport features into stable distributions,
// and new features targeting Rolling should not use this.
// See the comment in node.cpp for more information.
std::shared_ptr<NodeImpl> hidden_impl_{nullptr};
};
} // namespace rclcpp

View File

@@ -40,6 +40,7 @@
#include "rclcpp/create_generic_subscription.hpp"
#include "rclcpp/create_publisher.hpp"
#include "rclcpp/create_service.hpp"
#include "rclcpp/create_generic_service.hpp"
#include "rclcpp/create_subscription.hpp"
#include "rclcpp/create_timer.hpp"
#include "rclcpp/detail/resolve_enable_topic_statistics.hpp"
@@ -110,9 +111,27 @@ typename rclcpp::WallTimer<CallbackT>::SharedPtr
Node::create_wall_timer(
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group)
const rclcpp::CallbackGroup::SharedPtr & group,
bool autostart)
{
return rclcpp::create_wall_timer(
period,
std::move(callback),
group,
this->node_base_.get(),
this->node_timers_.get(),
autostart);
}
template<typename DurationRepT, typename DurationT, typename CallbackT>
typename rclcpp::GenericTimer<CallbackT>::SharedPtr
Node::create_timer(
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
const rclcpp::CallbackGroup::SharedPtr & group)
{
return rclcpp::create_timer(
this->get_clock(),
period,
std::move(callback),
group,
@@ -124,15 +143,15 @@ template<typename ServiceT>
typename Client<ServiceT>::SharedPtr
Node::create_client(
const std::string & service_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group)
const rclcpp::QoS & qos,
const rclcpp::CallbackGroup::SharedPtr & group)
{
return rclcpp::create_client<ServiceT>(
node_base_,
node_graph_,
node_services_,
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
qos_profile,
qos,
group);
}
@@ -141,15 +160,34 @@ typename rclcpp::Service<ServiceT>::SharedPtr
Node::create_service(
const std::string & service_name,
CallbackT && callback,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group)
const rclcpp::QoS & qos,
const rclcpp::CallbackGroup::SharedPtr & group)
{
return rclcpp::create_service<ServiceT, CallbackT>(
node_base_,
node_services_,
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
std::forward<CallbackT>(callback),
qos_profile,
qos,
group);
}
template<typename CallbackT>
typename rclcpp::GenericService::SharedPtr
Node::create_generic_service(
const std::string & service_name,
const std::string & service_type,
CallbackT && callback,
const rclcpp::QoS & qos,
const rclcpp::CallbackGroup::SharedPtr & group)
{
return rclcpp::create_generic_service<CallbackT>(
node_base_,
node_services_,
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
service_type,
std::forward<CallbackT>(callback),
qos,
group);
}
@@ -170,13 +208,13 @@ Node::create_generic_publisher(
);
}
template<typename AllocatorT>
template<typename CallbackT, 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,
CallbackT && callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options)
{
return rclcpp::create_generic_subscription(
@@ -184,7 +222,7 @@ Node::create_generic_subscription(
extend_name_with_sub_namespace(topic_name, this->get_sub_namespace()),
topic_type,
qos,
std::move(callback),
std::forward<CallbackT>(callback),
options
);
}
@@ -220,12 +258,16 @@ Node::declare_parameter(
// 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>();
try {
return this->declare_parameter(
name,
value.get_type(),
parameter_descriptor,
ignore_override
).get<ParameterT>();
} catch (const ParameterTypeException &) {
throw exceptions::UninitializedStaticallyTypedParameterException(name);
}
}
template<typename ParameterT>
@@ -281,11 +323,9 @@ template<typename ParameterT>
bool
Node::get_parameter(const std::string & name, ParameterT & parameter) const
{
std::string sub_name = extend_name_with_sub_namespace(name, this->get_sub_namespace());
rclcpp::Parameter parameter_variant;
bool result = get_parameter(sub_name, parameter_variant);
bool result = get_parameter(name, parameter_variant);
if (result) {
parameter = static_cast<ParameterT>(parameter_variant.get_value<ParameterT>());
}
@@ -300,15 +340,24 @@ Node::get_parameter_or(
ParameterT & parameter,
const ParameterT & alternative_value) const
{
std::string sub_name = extend_name_with_sub_namespace(name, this->get_sub_namespace());
bool got_parameter = get_parameter(sub_name, parameter);
bool got_parameter = get_parameter(name, parameter);
if (!got_parameter) {
parameter = alternative_value;
}
return got_parameter;
}
template<typename ParameterT>
ParameterT
Node::get_parameter_or(
const std::string & name,
const ParameterT & alternative_value) const
{
ParameterT parameter;
get_parameter_or(name, parameter, alternative_value);
return parameter;
}
// this is a partially-specialized version of get_parameter above,
// where our concrete type for ParameterT is std::map, but the to-be-determined
// type is the value in the map.

View File

@@ -0,0 +1,216 @@
// Copyright 2022 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__NODE_INTERFACES__DETAIL__NODE_INTERFACES_HELPERS_HPP_
#define RCLCPP__NODE_INTERFACES__DETAIL__NODE_INTERFACES_HELPERS_HPP_
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace node_interfaces
{
namespace detail
{
// Support and Helper template classes for the NodeInterfaces class.
template<typename NodeT, typename ... Ts>
std::tuple<std::shared_ptr<Ts>...>
init_tuple(NodeT & n);
/// Stores the interfaces in a tuple, provides constructors, and getters.
template<typename ... InterfaceTs>
struct NodeInterfacesStorage
{
template<typename NodeT>
NodeInterfacesStorage(NodeT & node) // NOLINT(runtime/explicit)
: interfaces_(init_tuple<decltype(node), InterfaceTs ...>(node))
{}
NodeInterfacesStorage()
: interfaces_()
{}
explicit NodeInterfacesStorage(std::shared_ptr<InterfaceTs>... args)
: interfaces_(args ...)
{}
/// Individual Node Interface non-const getter.
template<typename NodeInterfaceT>
std::shared_ptr<NodeInterfaceT>
get()
{
static_assert(
(std::is_same_v<NodeInterfaceT, InterfaceTs>|| ...),
"NodeInterfaces class does not contain given NodeInterfaceT");
return std::get<std::shared_ptr<NodeInterfaceT>>(interfaces_);
}
/// Individual Node Interface const getter.
template<typename NodeInterfaceT>
std::shared_ptr<const NodeInterfaceT>
get() const
{
static_assert(
(std::is_same_v<NodeInterfaceT, InterfaceTs>|| ...),
"NodeInterfaces class does not contain given NodeInterfaceT");
return std::get<std::shared_ptr<NodeInterfaceT>>(interfaces_);
}
protected:
std::tuple<std::shared_ptr<InterfaceTs>...> interfaces_;
};
/// Prototype of NodeInterfacesSupports.
/**
* Should read NodeInterfacesSupports<..., T, ...> as "NodeInterfaces supports T", and
* if NodeInterfacesSupport is specialized for T, the is_supported should be
* set to std::true_type, but by default it is std::false_type, which will
* lead to a compiler error when trying to use T with NodeInterfaces.
*/
template<typename StorageClassT, typename ... Ts>
struct NodeInterfacesSupports;
/// Prototype of NodeInterfacesSupportCheck template meta-function.
/**
* This meta-function checks that all the types given are supported,
* throwing a more human-readable error if an unsupported type is used.
*/
template<typename StorageClassT, typename ... InterfaceTs>
struct NodeInterfacesSupportCheck;
/// Iterating specialization that ensures classes are supported and inherited.
template<typename StorageClassT, typename NextInterfaceT, typename ... RemainingInterfaceTs>
struct NodeInterfacesSupportCheck<StorageClassT, NextInterfaceT, RemainingInterfaceTs ...>
: public NodeInterfacesSupportCheck<StorageClassT, RemainingInterfaceTs ...>
{
static_assert(
NodeInterfacesSupports<StorageClassT, NextInterfaceT>::is_supported::value,
"given NodeInterfaceT is not supported by rclcpp::node_interfaces::NodeInterfaces");
};
/// Terminating case when there are no more "RemainingInterfaceTs".
template<typename StorageClassT>
struct NodeInterfacesSupportCheck<StorageClassT>
{};
/// Default specialization, needs to be specialized for each supported interface.
template<typename StorageClassT, typename ... RemainingInterfaceTs>
struct NodeInterfacesSupports
{
// Specializations need to set this to std::true_type in addition to other interfaces.
using is_supported = std::false_type;
};
/// Terminating specialization of NodeInterfacesSupports.
template<typename StorageClassT>
struct NodeInterfacesSupports<StorageClassT>
: public StorageClassT
{
/// Perfect forwarding constructor to get arguments down to StorageClassT.
template<typename ... ArgsT>
explicit NodeInterfacesSupports(ArgsT && ... args)
: StorageClassT(std::forward<ArgsT>(args) ...)
{}
};
// Helper functions to initialize the tuple in NodeInterfaces.
template<typename StorageClassT, typename ElementT, typename TupleT, typename NodeT>
void
init_element(TupleT & t, NodeT & n)
{
std::get<std::shared_ptr<ElementT>>(t) =
NodeInterfacesSupports<StorageClassT, ElementT>::get_from_node_like(n);
}
template<typename NodeT, typename ... Ts>
std::tuple<std::shared_ptr<Ts>...>
init_tuple(NodeT & n)
{
using StorageClassT = NodeInterfacesStorage<Ts ...>;
std::tuple<std::shared_ptr<Ts>...> t;
(init_element<StorageClassT, Ts>(t, n), ...);
return t;
}
/// Macro for creating specializations with less boilerplate.
/**
* You can use this macro to add support for your interface class if:
*
* - The standard getter is get_node_{NodeInterfaceName}_interface(), and
* - the getter returns a non-const shared_ptr<{NodeInterfaceType}>
*
* Examples of using this can be seen in the standard node interface headers
* in rclcpp, e.g. rclcpp/node_interfaces/node_base_interface.hpp has:
*
* RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeBaseInterface, base)
*
* If your interface has a non-standard getter, or you want to instrument it or
* something like that, then you'll need to create your own specialization of
* the NodeInterfacesSupports struct without this macro.
*/
// *INDENT-OFF*
#define RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(NodeInterfaceType, NodeInterfaceName) \
namespace rclcpp::node_interfaces::detail { \
template<typename StorageClassT, typename ... RemainingInterfaceTs> \
struct NodeInterfacesSupports< \
StorageClassT, \
NodeInterfaceType, \
RemainingInterfaceTs ...> \
: public NodeInterfacesSupports<StorageClassT, RemainingInterfaceTs ...> \
{ \
using is_supported = std::true_type; \
\
template<typename NodeT> \
static \
std::shared_ptr<NodeInterfaceType> \
get_from_node_like(NodeT & node_like) \
{ \
return node_like.get_node_ ## NodeInterfaceName ## _interface(); \
} \
\
/* Perfect forwarding constructor to get arguments down to StorageClassT (eventually). */ \
template<typename ... ArgsT> \
explicit NodeInterfacesSupports(ArgsT && ... args) \
: NodeInterfacesSupports<StorageClassT, RemainingInterfaceTs ...>( \
std::forward<ArgsT>(args) ...) \
{} \
\
std::shared_ptr<NodeInterfaceType> \
get_node_ ## NodeInterfaceName ## _interface() \
{ \
return StorageClassT::template get<NodeInterfaceType>(); \
} \
\
std::shared_ptr<const NodeInterfaceType> \
get_node_ ## NodeInterfaceName ## _interface() const \
{ \
return StorageClassT::template get<NodeInterfaceType>(); \
} \
}; \
} // namespace rclcpp::node_interfaces::detail
// *INDENT-ON*
} // namespace detail
} // namespace node_interfaces
} // namespace rclcpp
#endif // RCLCPP__NODE_INTERFACES__DETAIL__NODE_INTERFACES_HELPERS_HPP_

View File

@@ -15,7 +15,7 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
#include <functional>
#include <atomic>
#include <memory>
#include <mutex>
#include <string>
@@ -34,11 +34,18 @@ namespace node_interfaces
{
/// Implementation of the NodeBase part of the Node API.
class NodeBase : public NodeBaseInterface
class NodeBase : public NodeBaseInterface, public std::enable_shared_from_this<NodeBase>
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeBase)
/// Constructor.
/**
* If nullptr (default) is given for the default_callback_group, one will
* be created by the constructor using the create_callback_group() method,
* but virtual dispatch will not occur so overrides of that method will not
* be used.
*/
RCLCPP_PUBLIC
NodeBase(
const std::string & node_name,
@@ -46,7 +53,8 @@ public:
rclcpp::Context::SharedPtr context,
const rcl_node_options_t & rcl_node_options,
bool use_intra_process_default,
bool enable_topic_statistics_default);
bool enable_topic_statistics_default,
rclcpp::CallbackGroup::SharedPtr default_callback_group = nullptr);
RCLCPP_PUBLIC
virtual
@@ -114,12 +122,12 @@ public:
get_associated_with_executor_atomic() override;
RCLCPP_PUBLIC
rcl_guard_condition_t *
get_notify_guard_condition() override;
rclcpp::GuardCondition::SharedPtr
get_shared_notify_guard_condition() override;
RCLCPP_PUBLIC
std::unique_lock<std::recursive_mutex>
acquire_notify_guard_condition_lock() const override;
void
trigger_notify_guard_condition() override;
RCLCPP_PUBLIC
bool
@@ -149,7 +157,7 @@ private:
/// Guard condition for notifying the Executor of changes to this node.
mutable std::recursive_mutex notify_guard_condition_mutex_;
rcl_guard_condition_t notify_guard_condition_ = rcl_get_zero_initialized_guard_condition();
std::shared_ptr<rclcpp::GuardCondition> notify_guard_condition_;
bool notify_guard_condition_is_valid_;
};

View File

@@ -15,16 +15,18 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
#include <atomic>
#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#include "rcl/node.h"
#include "rclcpp/callback_group.hpp"
#include "rclcpp/context.hpp"
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
@@ -142,23 +144,25 @@ public:
std::atomic_bool &
get_associated_with_executor_atomic() = 0;
/// Return guard condition that should be notified when the internal node state changes.
/// Return a guard condition that should be notified when the internal node state changes.
/**
* For example, this should be notified when a publisher is added or removed.
*
* \return the rcl_guard_condition_t if it is valid, else nullptr
* \return the GuardCondition if it is valid, else nullptr
*/
RCLCPP_PUBLIC
virtual
rcl_guard_condition_t *
get_notify_guard_condition() = 0;
rclcpp::GuardCondition::SharedPtr
get_shared_notify_guard_condition() = 0;
/// Acquire and return a scoped lock that protects the notify guard condition.
/** This should be used when triggering the notify guard condition. */
/// Trigger the guard condition that notifies of internal node state changes.
/**
* For example, this should be notified when a publisher is added or removed.
*/
RCLCPP_PUBLIC
virtual
std::unique_lock<std::recursive_mutex>
acquire_notify_guard_condition_lock() const = 0;
void
trigger_notify_guard_condition() = 0;
/// Return the default preference for using intra process communication.
RCLCPP_PUBLIC
@@ -183,4 +187,6 @@ public:
} // namespace node_interfaces
} // namespace rclcpp
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeBaseInterface, base)
#endif // RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_

View File

@@ -15,6 +15,7 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_CLOCK_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_CLOCK_HPP_
#include "rcl/time.h"
#include "rclcpp/clock.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
@@ -42,7 +43,8 @@ public:
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services,
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging);
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
rcl_clock_type_t clock_type);
RCLCPP_PUBLIC
virtual
@@ -67,7 +69,7 @@ private:
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_;
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging_;
rclcpp::Clock::SharedPtr ros_clock_;
rclcpp::Clock::SharedPtr clock_;
};
} // namespace node_interfaces

View File

@@ -17,6 +17,7 @@
#include "rclcpp/clock.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
@@ -50,4 +51,6 @@ public:
} // namespace node_interfaces
} // namespace rclcpp
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeClockInterface, clock)
#endif // RCLCPP__NODE_INTERFACES__NODE_CLOCK_INTERFACE_HPP_

View File

@@ -15,11 +15,14 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_GRAPH_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_GRAPH_HPP_
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
@@ -30,6 +33,7 @@
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rmw/service_endpoint_info_array.h"
#include "rmw/topic_endpoint_info_array.h"
namespace rclcpp
@@ -70,10 +74,34 @@ public:
const std::string & node_name,
const std::string & namespace_) const override;
RCLCPP_PUBLIC
std::map<std::string, std::vector<std::string>>
get_client_names_and_types_by_node(
const std::string & node_name,
const std::string & namespace_) const override;
RCLCPP_PUBLIC
std::map<std::string, std::vector<std::string>>
get_publisher_names_and_types_by_node(
const std::string & node_name,
const std::string & namespace_,
bool no_demangle = false) const override;
RCLCPP_PUBLIC
std::map<std::string, std::vector<std::string>>
get_subscriber_names_and_types_by_node(
const std::string & node_name,
const std::string & namespace_,
bool no_demangle = false) const override;
RCLCPP_PUBLIC
std::vector<std::string>
get_node_names() const override;
RCLCPP_PUBLIC
std::vector<std::tuple<std::string, std::string, std::string>>
get_node_names_with_enclaves() const override;
RCLCPP_PUBLIC
std::vector<std::pair<std::string, std::string>>
get_node_names_and_namespaces() const override;
@@ -86,6 +114,14 @@ public:
size_t
count_subscribers(const std::string & topic_name) const override;
RCLCPP_PUBLIC
size_t
count_clients(const std::string & service_name) const override;
RCLCPP_PUBLIC
size_t
count_services(const std::string & service_name) const override;
RCLCPP_PUBLIC
const rcl_guard_condition_t *
get_graph_guard_condition() const override;
@@ -124,14 +160,24 @@ public:
const std::string & topic_name,
bool no_mangle = false) const override;
RCLCPP_PUBLIC
std::vector<rclcpp::ServiceEndpointInfo>
get_clients_info_by_service(
const std::string & service_name,
bool no_mangle = false) const override;
RCLCPP_PUBLIC
std::vector<rclcpp::ServiceEndpointInfo>
get_servers_info_by_service(
const std::string & service_name,
bool no_mangle = false) const override;
private:
RCLCPP_DISABLE_COPY(NodeGraph)
/// Handle to the NodeBaseInterface given in the constructor.
rclcpp::node_interfaces::NodeBaseInterface * node_base_;
/// Graph Listener which waits on graph changes for the node and is shared across nodes.
std::shared_ptr<rclcpp::graph_listener::GraphListener> graph_listener_;
/// Whether or not this node needs to be added to the graph listener.
std::atomic_bool should_add_to_graph_listener_;

View File

@@ -18,8 +18,11 @@
#include <algorithm>
#include <array>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <map>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
@@ -28,6 +31,7 @@
#include "rclcpp/event.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -38,7 +42,9 @@ enum class EndpointType
{
Invalid = RMW_ENDPOINT_INVALID,
Publisher = RMW_ENDPOINT_PUBLISHER,
Subscription = RMW_ENDPOINT_SUBSCRIPTION
Subscription = RMW_ENDPOINT_SUBSCRIPTION,
Client = RMW_ENDPOINT_CLIENT,
Server = RMW_ENDPOINT_SERVER
};
/**
@@ -51,12 +57,17 @@ public:
/// Construct a TopicEndpointInfo from a rcl_topic_endpoint_info_t.
RCLCPP_PUBLIC
explicit TopicEndpointInfo(const rcl_topic_endpoint_info_t & info)
: node_name_(info.node_name),
node_namespace_(info.node_namespace),
topic_type_(info.topic_type),
endpoint_type_(static_cast<rclcpp::EndpointType>(info.endpoint_type)),
qos_profile_({info.qos_profile.history, info.qos_profile.depth}, info.qos_profile)
: endpoint_type_(static_cast<rclcpp::EndpointType>(info.endpoint_type)),
qos_profile_({info.qos_profile.history, info.qos_profile.depth}, info.qos_profile),
topic_type_hash_(info.topic_type_hash)
{
if (!info.node_name || !info.node_namespace || !info.topic_type) {
throw std::invalid_argument("Constructor TopicEndpointInfo with invalid topic endpoint info");
}
node_name_ = info.node_name;
node_namespace_ = info.node_namespace;
topic_type_ = info.topic_type;
std::copy(info.endpoint_gid, info.endpoint_gid + RMW_GID_STORAGE_SIZE, endpoint_gid_.begin());
}
@@ -120,6 +131,16 @@ public:
const rclcpp::QoS &
qos_profile() const;
/// Get a mutable reference to the type hash of the topic endpoint.
RCLCPP_PUBLIC
rosidl_type_hash_t &
topic_type_hash();
/// Get a const reference to the type hash of the topic endpoint.
RCLCPP_PUBLIC
const rosidl_type_hash_t &
topic_type_hash() const;
private:
std::string node_name_;
std::string node_namespace_;
@@ -127,6 +148,126 @@ private:
rclcpp::EndpointType endpoint_type_;
std::array<uint8_t, RMW_GID_STORAGE_SIZE> endpoint_gid_;
rclcpp::QoS qos_profile_;
rosidl_type_hash_t topic_type_hash_;
};
/**
* Struct that contains service endpoint information like the associated node name, node namespace,
* service type, endpoint type, endpoint count, endpoint GIDs, and its QoS profiles.
*/
class ServiceEndpointInfo
{
public:
/// Construct a ServiceEndpointInfo from a rcl_service_endpoint_info_t.
RCLCPP_PUBLIC
explicit ServiceEndpointInfo(const rcl_service_endpoint_info_t & info)
: node_name_(info.node_name),
node_namespace_(info.node_namespace),
service_type_(info.service_type),
endpoint_type_(static_cast<rclcpp::EndpointType>(info.endpoint_type)),
service_type_hash_(info.service_type_hash),
endpoint_count_(info.endpoint_count)
{
for(size_t i = 0; i < endpoint_count_; i++) {
std::array<uint8_t, RMW_GID_STORAGE_SIZE> gid;
std::copy(info.endpoint_gids[i], info.endpoint_gids[i] + RMW_GID_STORAGE_SIZE, gid.begin());
endpoint_gids_.push_back(gid);
rclcpp::QoS qos(
{info.qos_profiles[i].history, info.qos_profiles[i].depth}, info.qos_profiles[i]);
qos_profiles_.push_back(qos);
}
}
/// Get a mutable reference to the node name.
RCLCPP_PUBLIC
std::string &
node_name();
/// Get a const reference to the node name.
RCLCPP_PUBLIC
const std::string &
node_name() const;
/// Get a mutable reference to the node namespace.
RCLCPP_PUBLIC
std::string &
node_namespace();
/// Get a const reference to the node namespace.
RCLCPP_PUBLIC
const std::string &
node_namespace() const;
/// Get a mutable reference to the service type string.
RCLCPP_PUBLIC
std::string &
service_type();
/// Get a const reference to the service type string.
RCLCPP_PUBLIC
const std::string &
service_type() const;
/// Get a mutable reference to the service endpoint type.
RCLCPP_PUBLIC
rclcpp::EndpointType &
endpoint_type();
/// Get a const reference to the service endpoint type.
RCLCPP_PUBLIC
const rclcpp::EndpointType &
endpoint_type() const;
/// Get a mutable reference to the endpoint count.
RCLCPP_PUBLIC
size_t &
endpoint_count();
/// Get a const reference to the endpoint count.
RCLCPP_PUBLIC
const size_t &
endpoint_count() const;
/// Get a mutable reference to the GID of the service endpoint.
RCLCPP_PUBLIC
std::vector<std::array<uint8_t, RMW_GID_STORAGE_SIZE>> &
endpoint_gids();
/// Get a const reference to the GID of the service endpoint.
RCLCPP_PUBLIC
const std::vector<std::array<uint8_t, RMW_GID_STORAGE_SIZE>> &
endpoint_gids() const;
/// Get a mutable reference to the QoS profile of the service endpoint.
RCLCPP_PUBLIC
std::vector<rclcpp::QoS> &
qos_profiles();
/// Get a const reference to the QoS profile of the service endpoint.
RCLCPP_PUBLIC
const std::vector<rclcpp::QoS> &
qos_profiles() const;
/// Get a mutable reference to the type hash of the service endpoint.
RCLCPP_PUBLIC
rosidl_type_hash_t &
service_type_hash();
/// Get a const reference to the type hash of the service endpoint.
RCLCPP_PUBLIC
const rosidl_type_hash_t &
service_type_hash() const;
private:
std::string node_name_;
std::string node_namespace_;
std::string service_type_;
rclcpp::EndpointType endpoint_type_;
std::vector<std::array<uint8_t, RMW_GID_STORAGE_SIZE>> endpoint_gids_;
std::vector<rclcpp::QoS> qos_profiles_;
rosidl_type_hash_t service_type_hash_;
size_t endpoint_count_;
};
namespace node_interfaces
@@ -146,7 +287,9 @@ public:
/**
* A topic is considered to exist when at least one publisher or subscriber
* exists for it, whether they be local or remote to this process.
* The returned names are the actual names used and do not have remap rules applied.
* The returned names are the actual names of the topics, either announced by another nodes or by this one.
* Attempting to create publishers or subscribers using names returned by this function may not
* result in the desired topic name being used depending on the remap rules in use.
*
* \param[in] no_demangle if true, topic names and types are not demangled
*/
@@ -160,7 +303,9 @@ public:
* A service is considered to exist when at least one service server or
* service client exists for it, whether they be local or remote to this
* process.
* The returned names are the actual names used and do not have remap rules applied.
* The returned names are the actual names of the services, either announced by another nodes or by this one.
* Attempting to create clients or services using names returned by this function may not result in
* the desired service name being used depending on the remap rules in use.
*/
RCLCPP_PUBLIC
virtual
@@ -170,7 +315,9 @@ public:
/// Return a map of existing service names to list of service types for a specific node.
/**
* This function only considers services - not clients.
* The returned names are the actual names used and do not have remap rules applied.
* The returned names are the actual names after remap rules applied.
* Attempting to create service clients using names returned by this function may not
* result in the desired service name being used depending on the remap rules in use.
*
* \param[in] node_name name of the node
* \param[in] namespace_ namespace of the node
@@ -182,18 +329,85 @@ public:
const std::string & node_name,
const std::string & namespace_) const = 0;
/// Return a map of existing service names and types with a specific node.
/**
* This function only considers clients - not service servers.
* The returned names are the actual names after remap rules applied.
* Attempting to create service servers using names returned by this function may not
* result in the desired service name being used depending on the remap rules in use.
*
* \param[in] node_name name of the node
* \param[in] namespace_ namespace of the node
*/
RCLCPP_PUBLIC
virtual
std::map<std::string, std::vector<std::string>>
get_client_names_and_types_by_node(
const std::string & node_name,
const std::string & namespace_) const = 0;
/// Return a map of existing topic names to list of topic types for a specific node.
/**
* This function only considers publishers - not subscribers.
* The returned names are the actual names after remap rules applied.
* Attempting to create publishers or subscribers using names returned by this function may not
* result in the desired topic name being used depending on the remap rules in use.
*
* \param[in] node_name name of the node
* \param[in] namespace_ namespace of the node
* \param[in] no_demangle if true, topic names and types are not demangled
*/
RCLCPP_PUBLIC
virtual
std::map<std::string, std::vector<std::string>>
get_publisher_names_and_types_by_node(
const std::string & node_name,
const std::string & namespace_,
bool no_demangle = false) const = 0;
/// Return a map of existing topic names to list of topic types for a specific node.
/**
* This function only considers subscribers - not publishers.
* The returned names are the actual names after remap rules applied.
* Attempting to create publishers or subscribers using names returned by this function may not
* result in the desired topic name being used depending on the remap rules in use.
*
* \param[in] node_name name of the node
* \param[in] namespace_ namespace of the node
* \param[in] no_demangle if true, topic names and types are not demangled
*/
RCLCPP_PUBLIC
virtual
std::map<std::string, std::vector<std::string>>
get_subscriber_names_and_types_by_node(
const std::string & node_name,
const std::string & namespace_,
bool no_demangle = false) const = 0;
/// Return a vector of existing node names (string).
/*
* The returned names are the actual names used and do not have remap rules applied.
* The returned names are the actual names after remap rules applied.
*/
RCLCPP_PUBLIC
virtual
std::vector<std::string>
get_node_names() const = 0;
/// Return a vector of existing node names, namespaces and enclaves (tuple of string).
/*
* The returned names are the actual names after remap rules applied.
* The enclaves contain the runtime security artifacts, those can be
* used to establish secured network.
* See https://design.ros2.org/articles/ros2_security_enclaves.html
*/
RCLCPP_PUBLIC
virtual
std::vector<std::tuple<std::string, std::string, std::string>>
get_node_names_with_enclaves() const = 0;
/// Return a vector of existing node names and namespaces (pair of string).
/*
* The returned names are the actual names used and do not have remap rules applied.
* The returned names are the actual names after remap rules applied.
*/
RCLCPP_PUBLIC
virtual
@@ -218,6 +432,24 @@ public:
size_t
count_subscribers(const std::string & topic_name) const = 0;
/// Return the number of clients created for a given service.
/*
* \param[in] service_name the actual service name used; it will not be automatically remapped.
*/
RCLCPP_PUBLIC
virtual
size_t
count_clients(const std::string & service_name) const = 0;
/// Return the number of services created for a given service.
/*
* \param[in] service_name the actual service name used; it will not be automatically remapped.
*/
RCLCPP_PUBLIC
virtual
size_t
count_services(const std::string & service_name) const = 0;
/// Return the rcl guard condition which is triggered when the ROS graph changes.
RCLCPP_PUBLIC
virtual
@@ -283,6 +515,8 @@ public:
/// Return the topic endpoint information about publishers on a given topic.
/**
* \param[in] topic_name the actual topic name used; it will not be automatically remapped.
* \param[in] no_mangle if `true`, `topic_name` needs to be a valid middleware topic name,
* otherwise it should be a valid ROS topic name.
* \sa rclcpp::Node::get_publishers_info_by_topic
*/
RCLCPP_PUBLIC
@@ -293,15 +527,43 @@ public:
/// Return the topic endpoint information about subscriptions on a given topic.
/**
* \param[in] topic_name the actual topic name used; it will not be automatically remapped.
* \param[in] no_mangle if `true`, `topic_name` needs to be a valid middleware topic name,
* otherwise it should be a valid ROS topic name.
* \sa rclcpp::Node::get_subscriptions_info_by_topic
*/
RCLCPP_PUBLIC
virtual
std::vector<rclcpp::TopicEndpointInfo>
get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle = false) const = 0;
/// Return the service endpoint information about clients on a given service.
/**
* \param[in] service_name the actual service name used; it will not be automatically remapped.
* \param[in] no_mangle if `true`, `service_name` needs to be a valid middleware service name,
* otherwise it should be a valid ROS service name.
* \sa rclcpp::Node::get_clients_info_by_service
*/
RCLCPP_PUBLIC
virtual
std::vector<rclcpp::ServiceEndpointInfo>
get_clients_info_by_service(const std::string & service_name, bool no_mangle = false) const = 0;
/// Return the service endpoint information about servers on a given service.
/**
* \param[in] service_name the actual service name used; it will not be automatically remapped.
* \param[in] no_mangle if `true`, `service_name` needs to be a valid middleware service name,
* otherwise it should be a valid ROS service name.
* \sa rclcpp::Node::get_servers_info_by_service
*/
RCLCPP_PUBLIC
virtual
std::vector<rclcpp::ServiceEndpointInfo>
get_servers_info_by_service(const std::string & service_name, bool no_mangle = false) const = 0;
};
} // namespace node_interfaces
} // namespace rclcpp
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeGraphInterface, graph)
#endif // RCLCPP__NODE_INTERFACES__NODE_GRAPH_INTERFACE_HPP_

View File

@@ -0,0 +1,168 @@
// Copyright 2022 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__NODE_INTERFACES__NODE_INTERFACES_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_INTERFACES_HPP_
#include <memory>
#include "rclcpp/detail/template_unique.hpp"
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
#define ALL_RCLCPP_NODE_INTERFACES \
rclcpp::node_interfaces::NodeBaseInterface, \
rclcpp::node_interfaces::NodeClockInterface, \
rclcpp::node_interfaces::NodeGraphInterface, \
rclcpp::node_interfaces::NodeLoggingInterface, \
rclcpp::node_interfaces::NodeParametersInterface, \
rclcpp::node_interfaces::NodeServicesInterface, \
rclcpp::node_interfaces::NodeTimeSourceInterface, \
rclcpp::node_interfaces::NodeTimersInterface, \
rclcpp::node_interfaces::NodeTopicsInterface, \
rclcpp::node_interfaces::NodeTypeDescriptionsInterface, \
rclcpp::node_interfaces::NodeWaitablesInterface
namespace rclcpp
{
namespace node_interfaces
{
/// A helper class for aggregating node interfaces.
template<typename ... InterfaceTs>
class NodeInterfaces
: public detail::NodeInterfacesSupportCheck<
detail::NodeInterfacesStorage<InterfaceTs ...>,
InterfaceTs ...
>,
public detail::NodeInterfacesSupports<
detail::NodeInterfacesStorage<InterfaceTs ...>,
InterfaceTs ...
>
{
static_assert(
0 != sizeof ...(InterfaceTs),
"must provide at least one interface as a template argument");
static_assert(
rclcpp::detail::template_unique_v<InterfaceTs ...>,
"must provide unique template parameters");
using NodeInterfacesSupportsT = detail::NodeInterfacesSupports<
detail::NodeInterfacesStorage<InterfaceTs ...>,
InterfaceTs ...
>;
public:
/// Create a new NodeInterfaces object using the given node-like object's interfaces.
/**
* Specify which interfaces you need by passing them as template parameters.
*
* This allows you to aggregate interfaces from different sources together to pass as a single
* aggregate object to any functions that take node interfaces or node-likes, without needing to
* templatize that function.
*
* You may also use this constructor to create a NodeInterfaces that contains a subset of
* another NodeInterfaces' interfaces.
*
* Finally, this class supports implicit conversion from node-like objects, allowing you to
* directly pass a node-like to a function that takes a NodeInterfaces object.
*
* Usage examples:
* ```cpp
* // Suppose we have some function:
* void fn(NodeInterfaces<NodeBaseInterface, NodeClockInterface> interfaces);
*
* // Then we can, explicitly:
* rclcpp::Node node("some_node");
* auto ni = NodeInterfaces<NodeBaseInterface, NodeClockInterface>(node);
* fn(ni);
*
* // But also:
* fn(node);
*
* // Subsetting a NodeInterfaces object also works!
* auto ni_base = NodeInterfaces<NodeBaseInterface>(ni);
*
* // Or aggregate them (you could aggregate interfaces from disparate node-likes)
* auto ni_aggregated = NodeInterfaces<NodeBaseInterface, NodeClockInterface>(
* node->get_node_base_interface(),
* node->get_node_clock_interface()
* )
*
* // And then to access the interfaces:
* // Get with get<>
* auto base = ni.get<NodeBaseInterface>();
*
* // Or the appropriate getter
* auto clock = ni.get_clock_interface();
* ```
*
* You may use any of the standard node interfaces that come with rclcpp:
* - rclcpp::node_interfaces::NodeBaseInterface
* - rclcpp::node_interfaces::NodeClockInterface
* - rclcpp::node_interfaces::NodeGraphInterface
* - rclcpp::node_interfaces::NodeLoggingInterface
* - rclcpp::node_interfaces::NodeParametersInterface
* - rclcpp::node_interfaces::NodeServicesInterface
* - rclcpp::node_interfaces::NodeTimeSourceInterface
* - rclcpp::node_interfaces::NodeTimersInterface
* - rclcpp::node_interfaces::NodeTopicsInterface
* - rclcpp::node_interfaces::NodeTypeDescriptionsInterface
* - rclcpp::node_interfaces::NodeWaitablesInterface
*
* Or you use custom interfaces as long as you make a template specialization
* of the rclcpp::node_interfaces::detail::NodeInterfacesSupport struct using
* the RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT macro.
*
* Usage example:
* ```cpp
* RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeBaseInterface, base)
* ```
*
* If you choose not to use the helper macro, then you can specialize the
* template yourself, but you must:
*
* - Provide a template specialization of the get_from_node_like method that gets the interface
* from any node-like that stores the interface, using the node-like's getter
* - Designate the is_supported type as std::true_type using a using directive
* - Provide any number of getter methods to be used to obtain the interface with the
* NodeInterface object, noting that the getters of the storage class will apply to all
* supported interfaces.
* - The getter method names should not clash in name with any other interface getter
* specializations if those other interfaces are meant to be aggregated in the same
* NodeInterfaces object.
*
* \param[in] node Node-like object from which to get the node interfaces
*/
template<typename NodeT>
NodeInterfaces(NodeT & node) // NOLINT(runtime/explicit)
: NodeInterfacesSupportsT(node)
{}
// Create a NodeInterfaces object with no bound interfaces
NodeInterfaces()
: NodeInterfacesSupportsT()
{}
explicit NodeInterfaces(std::shared_ptr<InterfaceTs>... args)
: NodeInterfacesSupportsT(args ...)
{}
};
} // namespace node_interfaces
} // namespace rclcpp
#endif // RCLCPP__NODE_INTERFACES__NODE_INTERFACES_HPP_

View File

@@ -23,6 +23,9 @@
#include "rclcpp/node_interfaces/node_logging_interface.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rcl_interfaces/srv/get_logger_levels.hpp"
#include "rcl_interfaces/srv/set_logger_levels.hpp"
namespace rclcpp
{
namespace node_interfaces
@@ -35,7 +38,7 @@ public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeLoggingInterface)
RCLCPP_PUBLIC
explicit NodeLogging(rclcpp::node_interfaces::NodeBaseInterface * node_base);
explicit NodeLogging(const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_base);
RCLCPP_PUBLIC
virtual
@@ -49,13 +52,21 @@ public:
const char *
get_logger_name() const override;
RCLCPP_PUBLIC
void
create_logger_services(
const node_interfaces::NodeServicesInterface::SharedPtr & node_services) override;
private:
RCLCPP_DISABLE_COPY(NodeLogging)
/// Handle to the NodeBaseInterface given in the constructor.
rclcpp::node_interfaces::NodeBaseInterface * node_base_;
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_;
rclcpp::Logger logger_;
rclcpp::Service<rcl_interfaces::srv::GetLoggerLevels>::SharedPtr get_loggers_service_;
rclcpp::Service<rcl_interfaces::srv::SetLoggerLevels>::SharedPtr set_loggers_service_;
};
} // namespace node_interfaces

View File

@@ -19,6 +19,8 @@
#include "rclcpp/logger.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_services_interface.hpp"
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
@@ -37,21 +39,34 @@ public:
~NodeLoggingInterface() = default;
/// Return the logger of the node.
/** \return The logger of the node. */
/**
* \return The logger of the node.
*/
RCLCPP_PUBLIC
virtual
rclcpp::Logger
get_logger() const = 0;
/// Return the logger name associated with the node.
/** \return The logger name associated with the node. */
/**
* \return The logger name associated with the node.
*/
RCLCPP_PUBLIC
virtual
const char *
get_logger_name() const = 0;
/// create logger services
RCLCPP_PUBLIC
virtual
void
create_logger_services(
const node_interfaces::NodeServicesInterface::SharedPtr & node_services) = 0;
};
} // namespace node_interfaces
} // namespace rclcpp
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeLoggingInterface, logging)
#endif // RCLCPP__NODE_INTERFACES__NODE_LOGGING_INTERFACE_HPP_

View File

@@ -15,9 +15,10 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_HPP_
#include <list>
#include <map>
#include <memory>
#include <list>
#include <mutex>
#include <string>
#include <vector>
@@ -84,6 +85,16 @@ class NodeParameters : public NodeParametersInterface
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeParameters)
/// Constructor.
/**
* If using automatically_declare_parameters_from_overrides, overrides of
* get_parameter_overrides(), has_parameter(), declare_parameter() will not
* be respected.
* If this is an issue, pass false for
* automatically_declare_parameters_from_overrides and invoke
* perform_automatically_declare_parameters_from_overrides() manually after
* construction.
*/
RCLCPP_PUBLIC
NodeParameters(
const node_interfaces::NodeBaseInterface::SharedPtr node_base,
@@ -103,25 +114,6 @@ 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(
@@ -190,20 +182,52 @@ public:
rcl_interfaces::msg::ListParametersResult
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const override;
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
PreSetParametersCallbackHandle::SharedPtr
add_pre_set_parameters_callback(PreSetParametersCallbackType callback) override;
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
OnSetParametersCallbackHandle::SharedPtr
add_on_set_parameters_callback(OnParametersSetCallbackType callback) override;
add_on_set_parameters_callback(OnSetParametersCallbackType callback) override;
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
PostSetParametersCallbackHandle::SharedPtr
add_post_set_parameters_callback(PostSetParametersCallbackType callback) override;
RCLCPP_PUBLIC
void
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler) override;
RCLCPP_PUBLIC
void
remove_post_set_parameters_callback(const PostSetParametersCallbackHandle * const handler)
override;
RCLCPP_PUBLIC
void
remove_pre_set_parameters_callback(const PreSetParametersCallbackHandle * const handler) override;
RCLCPP_PUBLIC
const std::map<std::string, rclcpp::ParameterValue> &
get_parameter_overrides() const override;
using CallbacksContainerType = std::list<OnSetParametersCallbackHandle::WeakPtr>;
RCLCPP_PUBLIC
void
enable_parameter_modification() override;
using PreSetCallbacksHandleContainer = std::list<PreSetParametersCallbackHandle::WeakPtr>;
using OnSetCallbacksHandleContainer = std::list<OnSetParametersCallbackHandle::WeakPtr>;
using PostSetCallbacksHandleContainer = std::list<PostSetParametersCallbackHandle::WeakPtr>;
using CallbacksContainerType [[deprecated("use OnSetCallbacksHandleContainer instead")]] =
OnSetCallbacksHandleContainer;
protected:
RCLCPP_PUBLIC
void
perform_automatically_declare_parameters_from_overrides();
private:
RCLCPP_DISABLE_COPY(NodeParameters)
@@ -215,9 +239,11 @@ private:
// declare_parameter, etc). In those cases, this will be set to false.
bool parameter_modification_enabled_{true};
OnParametersSetCallbackType on_parameters_set_callback_ = nullptr;
PreSetCallbacksHandleContainer pre_set_parameters_callback_container_;
CallbacksContainerType on_parameters_set_callback_container_;
OnSetCallbacksHandleContainer on_set_parameters_callback_container_;
PostSetCallbacksHandleContainer post_set_parameters_callback_container_;
std::map<std::string, ParameterInfo> parameters_;

View File

@@ -15,8 +15,8 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <vector>
@@ -25,6 +25,7 @@
#include "rcl_interfaces/msg/set_parameters_result.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -33,28 +34,37 @@ namespace rclcpp
namespace node_interfaces
{
struct PreSetParametersCallbackHandle
{
RCLCPP_SMART_PTR_DEFINITIONS(PreSetParametersCallbackHandle)
using PreSetParametersCallbackType =
std::function<void (std::vector<rclcpp::Parameter> &)>;
PreSetParametersCallbackType callback;
};
struct OnSetParametersCallbackHandle
{
RCLCPP_SMART_PTR_DEFINITIONS(OnSetParametersCallbackHandle)
using OnParametersSetCallbackType =
using OnSetParametersCallbackType =
std::function<
rcl_interfaces::msg::SetParametersResult(
const std::vector<rclcpp::Parameter> &)>;
OnParametersSetCallbackType callback;
OnSetParametersCallbackType 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" \
"```"
struct PostSetParametersCallbackHandle
{
RCLCPP_SMART_PTR_DEFINITIONS(PostSetParametersCallbackHandle)
using PostSetParametersCallbackType =
std::function<void (const std::vector<rclcpp::Parameter> &)>;
PostSetParametersCallbackType callback;
};
/// Pure virtual interface class for the NodeParameters part of the Node API.
class NodeParametersInterface
@@ -66,15 +76,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
@@ -205,16 +206,46 @@ public:
rcl_interfaces::msg::ListParametersResult
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const = 0;
using OnParametersSetCallbackType = OnSetParametersCallbackHandle::OnParametersSetCallbackType;
using OnSetParametersCallbackType = OnSetParametersCallbackHandle::OnSetParametersCallbackType;
using PostSetParametersCallbackType =
PostSetParametersCallbackHandle::PostSetParametersCallbackType;
using PreSetParametersCallbackType = PreSetParametersCallbackHandle::PreSetParametersCallbackType;
/// Add a callback for when parameters are being set.
/// Add a callback that gets triggered before parameters are validated.
/**
* \sa rclcpp::Node::add_pre_set_parameters_callback
*/
RCLCPP_PUBLIC
virtual
PreSetParametersCallbackHandle::SharedPtr
add_pre_set_parameters_callback(PreSetParametersCallbackType callback) = 0;
/// Add a callback to validate parameters before they are set.
/**
* \sa rclcpp::Node::add_on_set_parameters_callback
*/
RCLCPP_PUBLIC
virtual
OnSetParametersCallbackHandle::SharedPtr
add_on_set_parameters_callback(OnParametersSetCallbackType callback) = 0;
add_on_set_parameters_callback(OnSetParametersCallbackType callback) = 0;
/// Add a callback that gets triggered after parameters are set successfully.
/**
* \sa rclcpp::Node::add_post_set_parameters_callback
*/
RCLCPP_PUBLIC
virtual
PostSetParametersCallbackHandle::SharedPtr
add_post_set_parameters_callback(PostSetParametersCallbackType callback) = 0;
/// Remove a callback registered with `add_pre_set_parameters_callback`.
/**
* \sa rclcpp::Node::remove_pre_set_parameters_callback
*/
RCLCPP_PUBLIC
virtual
void
remove_pre_set_parameters_callback(const PreSetParametersCallbackHandle * const handler) = 0;
/// Remove a callback registered with `add_on_set_parameters_callback`.
/**
@@ -225,14 +256,45 @@ public:
void
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler) = 0;
/// Remove a callback registered with `add_post_set_parameters_callback`.
/**
* \sa rclcpp::Node::remove_post_set_parameters_callback
*/
RCLCPP_PUBLIC
virtual
void
remove_post_set_parameters_callback(const PostSetParametersCallbackHandle * const handler) = 0;
/// Return the initial parameter values used by the NodeParameters to override default values.
RCLCPP_PUBLIC
virtual
const std::map<std::string, rclcpp::ParameterValue> &
get_parameter_overrides() const = 0;
/// Enable parameter modification recursively during parameter callbacks.
/**
* This function is used to enable parameter modification during parameter callbacks.
*
* There are times when it does not allow parameter modification, such as when the parameter
* callbacks are being called and tries to modify the parameters with set_parameter and
* declare_parameter to avoid recursive parameter modification.
* This is protected by rclcpp::node_interfaces::ParameterMutationRecursionGuard.
*
* This function is explicitly called to allow the recursive parameter operation during
* parameter callbacks by the application.
* Once it is enabled, the next parameter operation set/declare/undeclare_parameter are
* allowed to execute in the parameter callback. But, no more further recursive operation
* is allowed, unless user application calls this API again.
*/
RCLCPP_PUBLIC
virtual
void
enable_parameter_modification() = 0;
};
} // namespace node_interfaces
} // namespace rclcpp
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeParametersInterface, parameters)
#endif // RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_

View File

@@ -20,6 +20,7 @@
#include "rclcpp/callback_group.hpp"
#include "rclcpp/client.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
#include "rclcpp/service.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -62,4 +63,6 @@ public:
} // namespace node_interfaces
} // namespace rclcpp
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeServicesInterface, services)
#endif // RCLCPP__NODE_INTERFACES__NODE_SERVICES_INTERFACE_HPP_

View File

@@ -48,7 +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(),
const rclcpp::QoS & qos = rclcpp::ClockQoS(),
bool use_clock_thread = true
);

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