Compare commits

..

196 Commits

Author SHA1 Message Date
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
251 changed files with 11266 additions and 4275 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

@@ -1,13 +0,0 @@
name: Mirror rolling to master
on:
push:
branches: [ rolling ]
jobs:
mirror-to-master:
runs-on: ubuntu-latest
steps:
- uses: zofrex/mirror-branch@v1
with:
target-branch: master

View File

@@ -1,2 +0,0 @@
# This file was generated by https://github.com/audrow/update-ros2-repos
* @ivanpauno @hidmic @wjwwood

View File

@@ -2,14 +2,209 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
28.1.5 (2024-09-19)
30.1.3 (2025-11-18)
-------------------
* backport fix events-executor warm-up bug and add unit-tests (`#2591 <https://github.com/ros2/rclcpp/issues/2591>`_) (`#2628 <https://github.com/ros2/rclcpp/issues/2628>`_)
* Contributors: Alberto Soragna
* 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
28.1.4 (2024-09-06)
30.1.2 (2025-10-21)
-------------------
* Split test_executors.cpp even further. (`#2572 <https://github.com/ros2/rclcpp/issues/2572>`_) (`#2619 <https://github.com/ros2/rclcpp/issues/2619>`_)
* 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
@@ -17,70 +212,32 @@ Changelog for package rclcpp
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.
(cherry picked from commit c743c173e68d92af872cf163e10721a8dbe51dd0)
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
* Correct node name in service test code (`#2615 <https://github.com/ros2/rclcpp/issues/2615>`_) (`#2616 <https://github.com/ros2/rclcpp/issues/2616>`_)
(cherry picked from commit e846f56224a39b93f1c609e7ee03fff0662b7453)
Co-authored-by: Barry Xu <barry.xu@sony.com>
* Release ownership of entities after spinning cancelled (backport `#2556 <https://github.com/ros2/rclcpp/issues/2556>`_) (`#2580 <https://github.com/ros2/rclcpp/issues/2580>`_)
* 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
* 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
---------
(cherry picked from commit 069a0018935b33a14632a1cdf4074984a1cf80fe)
# Conflicts:
# rclcpp/test/rclcpp/executors/test_executors.cpp
* Fix backport issue (`#2581 <https://github.com/ros2/rclcpp/issues/2581>`_)
---------
Co-authored-by: Barry Xu <barry.xu@sony.com>
* Contributors: mergify[bot]
* Contributors: Alberto Soragna, Alejandro Hernández Cordero, Barry Xu, Chris Lalancette
28.1.3 (2024-06-27)
28.3.1 (2024-06-25)
-------------------
* 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>`_) (`#2552 <https://github.com/ros2/rclcpp/issues/2552>`_)
Co-authored-by: Mario Domínguez López <116071334+Mario-DL@users.noreply.github.com>
(cherry picked from commit 7c096888caf92aa7557e1d3efc5448b56d8ce81c)
Co-authored-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
* Contributors: mergify[bot]
* 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.1.2 (2024-05-13)
28.3.0 (2024-06-17)
-------------------
* add impl pointer for ExecutorOptions (`#2523 <https://github.com/ros2/rclcpp/issues/2523>`_) (`#2525 <https://github.com/ros2/rclcpp/issues/2525>`_)
* add impl pointer for ExecutorOptions
(cherry picked from commit 343b29b617b163ad72b9fe3f6441dd4ed3d3af09)
Co-authored-by: William Woodall <william@osrfoundation.org>
* Fixup Executor::spin_all() regression fix (`#2517 <https://github.com/ros2/rclcpp/issues/2517>`_) (`#2521 <https://github.com/ros2/rclcpp/issues/2521>`_)
* test(Executors): Added tests for busy waiting
Checks if executors are busy waiting while they should block
in spin_some or spin_all.
* 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.
* fix(Executor): Fixed spin_all not returning instantly is no work was available
* Update rclcpp/test/rclcpp/executors/test_executors.cpp
* test(executors): Added test for busy waiting while calling spin
* 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.
* restore previous test logic for now
* refactor spin_some_impl's logic and improve busy wait tests
* added some more comments about the implementation
---------
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>
Co-authored-by: William Woodall <william@osrfoundation.org>
* Contributors: mergify[bot]
* 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.1.1 (2024-04-24)
28.2.0 (2024-04-26)
-------------------
* Revise the description of service configure_introspection() (`#2511 <https://github.com/ros2/rclcpp/issues/2511>`_) (`#2513 <https://github.com/ros2/rclcpp/issues/2513>`_)
* Contributors: mergify[bot]
* 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)
-------------------

View File

@@ -70,13 +70,13 @@ set(${PROJECT_NAME}_SRCS
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_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
@@ -146,27 +146,6 @@ set(Python3_FIND_UNVERSIONED_NAMES FIRST)
find_package(Python3 REQUIRED COMPONENTS Interpreter)
# "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)
file(GLOB interface_files "include/rclcpp/node_interfaces/node_*_interface.hpp")
foreach(interface_file ${interface_files})
get_filename_component(interface_name ${interface_file} NAME_WE)

View File

@@ -21,6 +21,22 @@ GENERATE_LATEX = NO
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
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=

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 Requirements for Quality Level 1 in REP-2004](https://www.ros.org/reps/rep-2004.html).
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:
@@ -213,7 +213,7 @@ It is **Quality Level 1**, see its [Quality Declaration document](https://github
## 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

@@ -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.

View File

@@ -2,15 +2,15 @@
## 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 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.
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.
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.
@@ -19,11 +19,11 @@ We propose adding a `PostSetParametersCallbackHandle` for successful parameter s
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.
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.
* 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

@@ -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

@@ -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>();

View File

@@ -59,46 +59,6 @@ class CallbackGroup
public:
RCLCPP_SMART_PTR_DEFINITIONS(CallbackGroup)
/// Constructor for CallbackGroup.
/**
* Callback Groups have a type, either 'Mutually Exclusive' or 'Reentrant'
* and when creating one the type must be specified.
*
* Callbacks in Reentrant Callback Groups must be able to:
* - run at the same time as themselves (reentrant)
* - run at the same time as other callbacks in their group
* - run at the same time as other callbacks in other groups
*
* Callbacks in Mutually Exclusive Callback Groups:
* - will not be run multiple times simultaneously (non-reentrant)
* - will not be run at the same time as other callbacks in their group
* - but must run at the same time as callbacks in other groups
*
* Additionally, callback groups have a property which determines whether or
* not they are added to an executor with their associated node automatically.
* When creating a callback group the automatically_add_to_executor_with_node
* argument determines this behavior, and if true it will cause the newly
* created callback group to be added to an executor with the node when the
* Executor::add_node method is used.
* If false, this callback group will not be added automatically and would
* have to be added to an executor manually using the
* Executor::add_callback_group method.
*
* Whether the node was added to the executor before creating the callback
* group, or after, is irrelevant; the callback group will be automatically
* added to the executor in either case.
*
* \param[in] group_type The type of the callback group.
* \param[in] automatically_add_to_executor_with_node A boolean that
* determines whether a callback group is automatically added to an executor
* with the node with which it is associated.
*/
[[deprecated("Use CallbackGroup constructor with context function argument")]]
RCLCPP_PUBLIC
explicit CallbackGroup(
CallbackGroupType group_type,
bool automatically_add_to_executor_with_node = true);
/// Constructor for CallbackGroup.
/**
* Callback Groups have a type, either 'Mutually Exclusive' or 'Reentrant'

View File

@@ -70,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().
@@ -436,15 +428,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().
@@ -490,7 +473,7 @@ 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,
@@ -806,6 +789,9 @@ public:
* \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(

View File

@@ -60,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.
*/
@@ -193,16 +200,6 @@ public:
bool
ros_time_is_active();
/**
* Cancels an ongoing or future sleep operation of one thread.
*
* This function can be used by one thread, to wakeup another thread that is
* blocked using any of the sleep_ or wait_ methods of this class.
*/
RCLCPP_PUBLIC
void
cancel_sleep_or_wait();
/// Return the rcl_clock_t clock handle
RCLCPP_PUBLIC
rcl_clock_t *
@@ -217,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.
*
@@ -232,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
@@ -260,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,
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, 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

@@ -37,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
@@ -309,6 +313,10 @@ 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:
@@ -381,16 +389,19 @@ private:
std::recursive_mutex sub_contexts_mutex_;
std::vector<std::shared_ptr<OnShutdownCallback>> on_shutdown_callbacks_;
mutable std::mutex on_shutdown_callbacks_mutex_;
mutable std::recursive_mutex on_shutdown_callbacks_mutex_;
std::vector<std::shared_ptr<PreShutdownCallback>> pre_shutdown_callbacks_;
mutable std::mutex pre_shutdown_callbacks_mutex_;
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_;

View File

@@ -47,28 +47,9 @@ create_client(
const std::string & service_name,
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr)
{
return create_client<ServiceT>(
node_base, node_graph, node_services,
service_name,
qos.get_rmw_qos_profile(),
group);
}
/// Create a service client with a given type.
/// \internal
template<typename ServiceT>
typename rclcpp::Client<ServiceT>::SharedPtr
create_client(
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
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)
{
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(),
@@ -80,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,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

@@ -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 &) {

View File

@@ -20,6 +20,7 @@
#include <mutex>
#include <stdexcept>
#include <string>
#include <vector>
#include "rcl/error_handling.h"
#include "rcl/event_callback.h"
@@ -221,6 +222,13 @@ public:
}
}
RCLCPP_PUBLIC
std::vector<std::shared_ptr<rclcpp::TimerBase>>
get_timers() const override
{
return {};
}
protected:
RCLCPP_PUBLIC
void
@@ -233,8 +241,6 @@ protected:
size_t wait_set_event_index_;
};
using QOSEventHandlerBase [[deprecated("Use rclcpp::EventHandlerBase")]] = EventHandlerBase;
template<typename EventCallbackT, typename ParentHandleT>
class EventHandler : public EventHandlerBase
{
@@ -280,15 +286,15 @@ public:
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(size_t id) override
take_data_by_entity_id([[maybe_unused]] size_t id) override
{
(void)id;
return take_data();
}
@@ -311,11 +317,6 @@ private:
ParentHandleT parent_handle_;
EventCallbackT event_callback_;
};
template<typename EventCallbackT, typename ParentHandleT>
using QOSEventHandler [[deprecated("Use rclcpp::EventHandler")]] = EventHandler<EventCallbackT,
ParentHandleT>;
} // 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:

View File

@@ -287,6 +287,18 @@ public:
* 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
@@ -359,6 +371,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
@@ -541,8 +556,9 @@ protected:
*
* \param[in] notify if true will execute a trigger that will wake up a waiting executor
*/
void
trigger_entity_recollect(bool notify);
RCLCPP_PUBLIC
virtual void
handle_updated_entities(bool notify);
/// Spinning state, used to prevent multi threaded calls to spin and to cancel blocking spins.
std::atomic_bool spinning;

View File

@@ -20,7 +20,6 @@
#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"
@@ -29,24 +28,82 @@
namespace rclcpp
{
/// Create a default single-threaded executor and execute all available work exhaustively.
/** \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_all(
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_all(rclcpp::Node::SharedPtr node_ptr, std::chrono::nanoseconds max_duration);
/// 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 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(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(rclcpp::Node::SharedPtr node_ptr);

View File

@@ -19,6 +19,7 @@
#include <memory>
#include <mutex>
#include <set>
#include <vector>
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/waitable.hpp"
@@ -41,7 +42,9 @@ public:
* of this waitable has signaled the wait_set.
*/
RCLCPP_PUBLIC
explicit ExecutorNotifyWaitable(std::function<void(void)> on_execute_callback = {});
explicit ExecutorNotifyWaitable(
std::function<void(void)> on_execute_callback = {}, const rclcpp::Context::SharedPtr & context =
rclcpp::contexts::get_global_default_context());
// Destructor
RCLCPP_PUBLIC
@@ -122,6 +125,14 @@ 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.
@@ -138,17 +149,37 @@ 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::WeakPtr,
std::owner_less<rclcpp::GuardCondition::WeakPtr>> notify_guard_conditions_;
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

View File

@@ -1,138 +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 <atomic>
#include <chrono>
#include <memory>
#include "rclcpp/executor.hpp"
#include "rclcpp/executors/executor_entities_collection.hpp"
#include "rclcpp/executors/single_threaded_executor.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 destructor.
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 (must be >= 0)
* or no more work available.
* If timeout is `0`, potentially it blocks forever until no more work is 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;
protected:
/**
* @brief Executes ready executables from wait set.
* @param collection entities to evaluate for ready executables.
* @param wait_result result to check for ready executables.
* @param spin_once if true executes only the first ready executable.
* @return true if any executable was ready.
*/
bool
execute_ready_executables(
const rclcpp::executors::ExecutorEntitiesCollection & collection,
rclcpp::WaitResult<rclcpp::WaitSet> & wait_result,
bool spin_once);
void
spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive);
void
spin_once_impl(std::chrono::nanoseconds timeout) override;
std::optional<rclcpp::WaitResult<rclcpp::WaitSet>>
collect_and_wait(std::chrono::nanoseconds timeout);
private:
RCLCPP_DISABLE_COPY(StaticSingleThreadedExecutor)
};
} // namespace executors
} // namespace rclcpp
#endif // RCLCPP__EXECUTORS__STATIC_SINGLE_THREADED_EXECUTOR_HPP_

View File

@@ -178,6 +178,8 @@ public:
void clear() override
{
TRACETOOLS_TRACEPOINT(rclcpp_ring_buffer_clear, static_cast<const void *>(this));
std::lock_guard<std::mutex> lock(mutex_);
clear_();
}
private:
@@ -227,6 +229,14 @@ private:
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 {};
@@ -255,9 +265,13 @@ private:
std::vector<BufferT> result_vtr;
result_vtr.reserve(size_);
for (size_t id = 0; id < size_; ++id) {
result_vtr.emplace_back(
new typename is_std_unique_ptr<T>::Ptr_type(
*(ring_buffer_[(read_index_ + id) % capacity_])));
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;
}
@@ -292,7 +306,7 @@ private:
return {};
}
size_t capacity_;
const size_t capacity_;
std::vector<BufferT> ring_buffer_;

View File

@@ -59,24 +59,22 @@ namespace executors
*/
class EventsExecutor : public rclcpp::Executor
{
friend class EventsExecutorEntitiesCollector;
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.
* \param[in] options Options used to configure the executor.
*/
RCLCPP_PUBLIC
explicit EventsExecutor(
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,
const rclcpp::ExecutorOptions & options = rclcpp::ExecutorOptions());
bool execute_timers_separate_thread = false);
/// Default destructor.
RCLCPP_PUBLIC
@@ -128,87 +126,6 @@ public:
void
spin_all(std::chrono::nanoseconds max_duration) 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::EventsExecutor::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;
/// 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;
/// Get callback groups that belong to executor.
/**
* \sa rclcpp::Executor::get_all_callback_groups()
*/
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:
/// Internal implementation of spin_once
RCLCPP_PUBLIC
@@ -220,6 +137,11 @@ protected:
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)
@@ -227,9 +149,9 @@ private:
void
execute_event(const ExecutorEvent & event);
/// Collect entities from callback groups and refresh the current collection with them
/// Rebuilds the executor's notify waitable, as we can't use the one built in the base class
void
refresh_current_collection_from_callback_groups();
setup_notify_waitable();
/// Refresh the current collection using the provided new_collection
void
@@ -253,6 +175,11 @@ private:
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()) {
@@ -273,16 +200,6 @@ private:
/// Queue where entities can push events
rclcpp::experimental::executors::EventsQueue::UniquePtr events_queue_;
std::shared_ptr<rclcpp::executors::ExecutorEntitiesCollector> entities_collector_;
std::shared_ptr<rclcpp::executors::ExecutorNotifyWaitable> notify_waitable_;
/// Mutex to protect the current_entities_collection_
std::recursive_mutex collection_mutex_;
std::shared_ptr<rclcpp::executors::ExecutorEntitiesCollection> current_entities_collection_;
/// Flag used to reduce the number of unnecessary waitable events
std::atomic<bool> notify_waitable_event_pushed_ {false};
/// Timers manager used to track and/or execute associated timers
std::shared_ptr<rclcpp::experimental::TimersManager> timers_manager_;
};

View File

@@ -19,6 +19,7 @@
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#include "rcl/wait.h"
#include "rmw/impl/cpp/demangle.hpp"
@@ -78,9 +79,8 @@ public:
take_data() override = 0;
std::shared_ptr<void>
take_data_by_entity_id(size_t id) override
take_data_by_entity_id([[maybe_unused]] size_t id) override
{
(void)id;
return take_data();
}
@@ -180,6 +180,13 @@ public:
on_new_message_callback_ = nullptr;
}
RCLCPP_PUBLIC
std::vector<std::shared_ptr<rclcpp::TimerBase>>
get_timers() const override
{
return {};
}
protected:
std::recursive_mutex callback_mutex_;
std::function<void(size_t)> on_new_message_callback_ {nullptr};

View File

@@ -110,9 +110,8 @@ public:
}
bool
is_ready(const rcl_wait_set_t & wait_set) override
is_ready([[maybe_unused]] const rcl_wait_set_t & wait_set) override
{
(void) wait_set;
return buffer_->has_data();
}

View File

@@ -19,6 +19,7 @@
#include <memory>
#include <future>
#include <string>
#include <tuple>
#include <vector>
#include <utility>
@@ -35,8 +36,8 @@ namespace rclcpp
class GenericClient : public ClientBase
{
public:
using Request = void *; // Serialized data pointer of request message
using Response = void *; // Serialized data pointer of response message
using Request = void *; // Deserialized data pointer of request message
using Response = void *; // Deserialized data pointer of response message
using SharedResponse = std::shared_ptr<void>;
@@ -46,6 +47,8 @@ public:
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.
@@ -76,6 +79,20 @@ public:
~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,
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
@@ -106,16 +123,16 @@ public:
* 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 `Client` instance to use more memory each time a response is not
* received from the service server.
* 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 = client->async_send_request(my_request);
* auto future = generic_client->async_send_request(my_request);
* if (
* rclcpp::FutureReturnCode::TIMEOUT ==
* executor->spin_until_future_complete(future, timeout))
* {
* client->remove_pending_request(future);
* generic_client->remove_pending_request(future);
* // handle timeout
* } else {
* handle_response(future.get());
@@ -129,6 +146,45 @@ 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.
@@ -149,15 +205,52 @@ public:
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().
@@ -179,9 +272,12 @@ public:
}
protected:
using CallbackTypeValueVariant = std::tuple<CallbackType, SharedFuture, Promise>;
using CallbackInfoVariant = std::variant<
std::promise<SharedResponse>>; // Use variant for extension
std::promise<SharedResponse>,
CallbackTypeValueVariant>; // Use variant for extension
RCLCPP_PUBLIC
int64_t
async_send_request_impl(
const Request request,

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), std::move(response));
} else if (std::holds_alternative<SharedPtrWithRequestHeaderCallback>(callback_)) {
const auto & cb = std::get<SharedPtrWithRequestHeaderCallback>(callback_);
cb(request_header, std::move(request), std::move(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(
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(
std::shared_ptr<rmw_request_id_t> request_header,
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

@@ -154,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
@@ -181,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_;

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,36 +81,6 @@ 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_)),

View File

@@ -15,6 +15,7 @@
#ifndef RCLCPP__LOGGER_HPP_
#define RCLCPP__LOGGER_HPP_
#include <filesystem>
#include <memory>
#include <string>
#include <utility>
@@ -86,8 +87,8 @@ get_node_logger(const rcl_node_t * node);
* \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
{

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

@@ -44,6 +44,7 @@
#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"
@@ -257,22 +258,6 @@ public:
CallbackT callback,
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.
* \return Shared pointer to the created client.
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
*/
template<typename ServiceT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
typename rclcpp::Client<ServiceT>::SharedPtr
create_client(
const std::string & service_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a Client.
/**
* \param[in] service_name The name on which the service is accessible.
@@ -287,24 +272,6 @@ public:
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
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] group Callback group to call the service.
* \return Shared pointer to the created service.
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
*/
template<typename ServiceT, typename CallbackT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
typename rclcpp::Service<ServiceT>::SharedPtr
create_service(
const std::string & service_name,
CallbackT && callback,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a Service.
/**
* \param[in] service_name The topic to service on.
@@ -337,6 +304,24 @@ public:
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
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(),
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a GenericPublisher.
/**
* The returned pointer will never be empty, but this function can throw various exceptions, for
@@ -1015,8 +1000,6 @@ public:
rclcpp::node_interfaces::OnSetParametersCallbackHandle;
using OnSetParametersCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::OnSetParametersCallbackType;
using OnParametersSetCallbackType [[deprecated("use OnSetParametersCallbackType instead")]] =
OnSetParametersCallbackType;
using PostSetParametersCallbackHandle =
rclcpp::node_interfaces::PostSetParametersCallbackHandle;
@@ -1405,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
@@ -1447,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
*/
@@ -1576,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.

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"
@@ -154,22 +155,6 @@ Node::create_client(
group);
}
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)
{
return rclcpp::create_client<ServiceT>(
node_base_,
node_graph_,
node_services_,
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
qos_profile,
group);
}
template<typename ServiceT, typename CallbackT>
typename rclcpp::Service<ServiceT>::SharedPtr
Node::create_service(
@@ -187,20 +172,22 @@ Node::create_service(
group);
}
template<typename ServiceT, typename CallbackT>
typename rclcpp::Service<ServiceT>::SharedPtr
Node::create_service(
template<typename CallbackT>
typename rclcpp::GenericService::SharedPtr
Node::create_generic_service(
const std::string & service_name,
const std::string & service_type,
CallbackT && callback,
const rmw_qos_profile_t & qos_profile,
const rclcpp::QoS & qos,
rclcpp::CallbackGroup::SharedPtr group)
{
return rclcpp::create_service<ServiceT, CallbackT>(
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_profile,
qos,
group);
}
@@ -336,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>());
}
@@ -355,9 +340,7 @@ 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;
}

View File

@@ -121,11 +121,6 @@ public:
std::atomic_bool &
get_associated_with_executor_atomic() override;
[[deprecated("Use get_shared_notify_guard_condition or trigger_notify_guard_condition instead")]]
RCLCPP_PUBLIC
rclcpp::GuardCondition &
get_notify_guard_condition() override;
RCLCPP_PUBLIC
rclcpp::GuardCondition::SharedPtr
get_shared_notify_guard_condition() override;

View File

@@ -144,17 +144,6 @@ public:
std::atomic_bool &
get_associated_with_executor_atomic() = 0;
/// 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 GuardCondition if it is valid, else throw runtime error
*/
RCLCPP_PUBLIC
virtual
rclcpp::GuardCondition &
get_notify_guard_condition() = 0;
/// 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.

View File

@@ -33,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
@@ -159,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,6 +18,8 @@
#include <algorithm>
#include <array>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <map>
#include <string>
#include <tuple>
@@ -40,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
};
/**
@@ -143,6 +147,125 @@ private:
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
{
@@ -408,6 +531,30 @@ 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

View File

@@ -214,6 +214,10 @@ public:
const std::map<std::string, rclcpp::ParameterValue> &
get_parameter_overrides() const override;
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>;

View File

@@ -52,8 +52,6 @@ struct OnSetParametersCallbackHandle
std::function<
rcl_interfaces::msg::SetParametersResult(
const std::vector<rclcpp::Parameter> &)>;
using OnParametersSetCallbackType [[deprecated("use OnSetParametersCallbackType instead")]] =
OnSetParametersCallbackType;
OnSetParametersCallbackType callback;
};
@@ -272,6 +270,26 @@ 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

View File

@@ -146,6 +146,14 @@ public:
return *this;
}
/// Append a single parameter override, parameter idiom style.
NodeOptions &
append_parameter_override(const rclcpp::Parameter & param)
{
this->parameter_overrides().push_back(param);
return *this;
}
/// Return the use_global_arguments flag.
RCLCPP_PUBLIC
bool

View File

@@ -52,37 +52,6 @@ class AsyncParametersClient
public:
RCLCPP_SMART_PTR_DEFINITIONS(AsyncParametersClient)
/// Create an async parameters client.
/**
* \param[in] node_base_interface The node base interface of the corresponding node.
* \param[in] node_topics_interface Node topic base interface.
* \param[in] node_graph_interface The node graph interface of the corresponding node.
* \param[in] node_services_interface Node service interface.
* \param[in] remote_node_name Name of the remote node
* \param[in] qos_profile The rmw qos profile to use to subscribe
* \param[in] group (optional) The async parameter client will be added to this callback group.
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
*/
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
RCLCPP_PUBLIC
AsyncParametersClient(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface,
const rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_interface,
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
: AsyncParametersClient(
node_base_interface,
node_topics_interface,
node_graph_interface,
node_services_interface,
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)),
group)
{}
/// Create an async parameters client.
/**
* \param[in] node_base_interface The node base interface of the corresponding node.
@@ -103,31 +72,6 @@ public:
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Constructor
/**
* \param[in] node The async parameters client will be added to this node.
* \param[in] remote_node_name name of the remote node
* \param[in] qos_profile The rmw qos profile to use to subscribe
* \param[in] group (optional) The async parameter client will be added to this callback group.
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
*/
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
AsyncParametersClient(
const std::shared_ptr<NodeT> node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
: AsyncParametersClient(
node->get_node_base_interface(),
node->get_node_topics_interface(),
node->get_node_graph_interface(),
node->get_node_services_interface(),
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)),
group)
{}
/**
* \param[in] node The async parameters client will be added to this node.
* \param[in] remote_node_name (optional) name of the remote node
@@ -150,31 +94,6 @@ public:
group)
{}
/// Constructor
/**
* \param[in] node The async parameters client will be added to this node.
* \param[in] remote_node_name Name of the remote node
* \param[in] qos_profile The rmw qos profile to use to subscribe
* \param[in] group (optional) The async parameter client will be added to this callback group.
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
*/
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
AsyncParametersClient(
NodeT * node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
: AsyncParametersClient(
node->get_node_base_interface(),
node->get_node_topics_interface(),
node->get_node_graph_interface(),
node->get_node_services_interface(),
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)),
group)
{}
/**
* \param[in] node The async parameters client will be added to this node.
* \param[in] remote_node_name (optional) name of the remote node
@@ -383,19 +302,6 @@ class SyncParametersClient
public:
RCLCPP_SMART_PTR_DEFINITIONS(SyncParametersClient)
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
SyncParametersClient(
std::shared_ptr<NodeT> node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile)
: SyncParametersClient(
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(),
node,
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
{}
template<typename NodeT>
explicit SyncParametersClient(
std::shared_ptr<NodeT> node,
@@ -408,23 +314,6 @@ public:
qos_profile)
{}
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
std::shared_ptr<NodeT> node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile)
: SyncParametersClient(
executor,
node->get_node_base_interface(),
node->get_node_topics_interface(),
node->get_node_graph_interface(),
node->get_node_services_interface(),
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
{}
template<typename NodeT>
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
@@ -441,19 +330,6 @@ public:
qos_profile)
{}
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
SyncParametersClient(
NodeT * node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile)
: SyncParametersClient(
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(),
node,
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
{}
template<typename NodeT>
explicit SyncParametersClient(
NodeT * node,
@@ -466,23 +342,6 @@ public:
qos_profile)
{}
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
NodeT * node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile)
: SyncParametersClient(
executor,
node->get_node_base_interface(),
node->get_node_topics_interface(),
node->get_node_graph_interface(),
node->get_node_services_interface(),
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
{}
template<typename NodeT>
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
@@ -499,28 +358,6 @@ public:
qos_profile)
{}
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
RCLCPP_PUBLIC
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface,
const rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_interface,
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile)
: executor_(executor), node_base_interface_(node_base_interface)
{
async_parameters_client_ =
std::make_shared<AsyncParametersClient>(
node_base_interface,
node_topics_interface,
node_graph_interface,
node_services_interface,
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)));
}
RCLCPP_PUBLIC
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,

View File

@@ -67,19 +67,23 @@ struct ParameterEventCallbackHandle
* The first step is to instantiate a ParameterEventHandler, providing a ROS node to use
* to create any required subscriptions:
*
* auto param_handler = std::make_shared<rclcpp::ParameterEventHandler>(node);
* ```cpp
* auto param_handler = std::make_shared<rclcpp::ParameterEventHandler>(node);
* ```
*
* Next, you can supply a callback to the add_parameter_callback method, as follows:
*
* auto cb1 = [&node](const rclcpp::Parameter & p) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb1: Received an update to parameter \"%s\" of type %s: \"%ld\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_int());
* };
* auto handle1 = param_handler->add_parameter_callback("an_int_param", cb1);
* ```cpp
* auto cb1 = [&node](const rclcpp::Parameter & p) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb1: Received an update to parameter \"%s\" of type %s: \"%ld\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_int());
* };
* auto handle1 = param_handler->add_parameter_callback("an_int_param", cb1);
* ```
*
* In this case, we didn't supply a node name (the third, optional, parameter) so the
* default will be to monitor for changes to the "an_int_param" parameter associated with
@@ -92,16 +96,18 @@ struct ParameterEventCallbackHandle
* You may also monitor for changes to parameters in other nodes by supplying the node
* name to add_parameter_callback:
*
* auto cb2 = [&node](const rclcpp::Parameter & p) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb2: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_string().c_str());
* };
* auto handle2 = param_handler->add_parameter_callback(
* "some_remote_param_name", cb2, "some_remote_node_name");
* ```cpp
* auto cb2 = [&node](const rclcpp::Parameter & p) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb2: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_string().c_str());
* };
* auto handle2 = param_handler->add_parameter_callback(
* "some_remote_param_name", cb2, "some_remote_node_name");
* ```
*
* In this case, the callback will be invoked whenever "some_remote_param_name" changes
* on remote node "some_remote_node_name".
@@ -109,7 +115,9 @@ struct ParameterEventCallbackHandle
* To remove a parameter callback, reset the callback handle smart pointer or call
* remove_parameter_callback, passing the handle returned from add_parameter_callback:
*
* param_handler->remove_parameter_callback(handle2);
* ```cpp
* param_handler->remove_parameter_callback(handle2);
* ```
*
* You can also monitor for *all* parameter changes, using add_parameter_event_callback.
* In this case, the callback will be invoked whenever any parameter changes in the system.
@@ -117,40 +125,42 @@ struct ParameterEventCallbackHandle
* is convenient to use a regular expression on the node names or namespaces of interest.
* For example:
*
* auto cb3 =
* [fqn, remote_param_name, &node](const rcl_interfaces::msg::ParameterEvent & event) {
* // Look for any updates to parameters in "/a_namespace" as well as any parameter changes
* // to our own node ("this_node")
* std::regex re("(/a_namespace/.*)|(/this_node)");
* if (regex_match(event.node, re)) {
* // Now that we know the event matches the regular expression we scanned for, we can
* // use 'get_parameter_from_event' to get a specific parameter name that we're looking for
* rclcpp::Parameter p;
* if (rclcpp::ParameterEventsSubscriber::get_parameter_from_event(
* event, p, remote_param_name, fqn))
* {
* RCLCPP_INFO(
* node->get_logger(),
* "cb3: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_string().c_str());
* }
*
* // You can also use 'get_parameter*s*_from_event' to enumerate all changes that came
* // in on this event
* auto params = rclcpp::ParameterEventsSubscriber::get_parameters_from_event(event);
* for (auto & p : params) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb3: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.value_to_string().c_str());
* }
* ```cpp
* auto cb3 =
* [fqn, remote_param_name, &node](const rcl_interfaces::msg::ParameterEvent & event) {
* // Look for any updates to parameters in "/a_namespace" as well as any parameter changes
* // to our own node ("this_node")
* std::regex re("(/a_namespace/.*)|(/this_node)");
* if (regex_match(event.node, re)) {
* // Now that we know the event matches the regular expression we scanned for, we can
* // use 'get_parameter_from_event' to get a specific parameter name that we're looking for
* rclcpp::Parameter p;
* if (rclcpp::ParameterEventHandler::get_parameter_from_event(
* event, p, remote_param_name, fqn))
* {
* RCLCPP_INFO(
* node->get_logger(),
* "cb3: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_string().c_str());
* }
* };
* auto handle3 = param_handler->add_parameter_event_callback(cb3);
*
* // You can also use 'get_parameter*s*_from_event' to enumerate all changes that came
* // in on this event
* auto params = rclcpp::ParameterEventHandler::get_parameters_from_event(event);
* for (auto & p : params) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb3: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.value_to_string().c_str());
* }
* }
* };
* auto handle3 = param_handler->add_parameter_event_callback(cb3);
* ```
*
* For both parameter callbacks and parameter event callbacks, when multiple callbacks are added,
* the callbacks are invoked last-in, first-called order (LIFO).
@@ -160,7 +170,9 @@ struct ParameterEventCallbackHandle
*
* To remove a parameter event callback, reset the callback smart pointer or use:
*
* param_handler->remove_event_parameter_callback(handle3);
* ```cpp
* param_handler->remove_event_parameter_callback(handle3);
* ```
*/
class ParameterEventHandler
{

View File

@@ -45,6 +45,7 @@ public:
* \param[in] names A list of parameter names of interest.
* \param[in] types A list of the types of parameter events of iterest.
* EventType NEW, DELETED, or CHANGED
* \throws std::invalid_argument if event is NULL.
*
* Example Usage:
*

View File

@@ -40,20 +40,6 @@ class ParameterService
public:
RCLCPP_SMART_PTR_DEFINITIONS(ParameterService)
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
RCLCPP_PUBLIC
ParameterService(
const std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
const std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
rclcpp::node_interfaces::NodeParametersInterface * node_params,
const rmw_qos_profile_t & qos_profile)
: ParameterService(
node_base,
node_services,
node_params,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
{}
RCLCPP_PUBLIC
ParameterService(
const std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,

View File

@@ -359,7 +359,7 @@ private:
/// Return the value of a parameter as a string
RCLCPP_PUBLIC
std::string
to_string(const ParameterValue & type);
to_string(const ParameterValue & value);
} // namespace rclcpp

View File

@@ -96,22 +96,6 @@ public:
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
using MessageAllocatorTraits
[[deprecated("use PublishedTypeAllocatorTraits")]] =
PublishedTypeAllocatorTraits;
using MessageAllocator
[[deprecated("use PublishedTypeAllocator")]] =
PublishedTypeAllocator;
using MessageDeleter
[[deprecated("use PublishedTypeDeleter")]] =
PublishedTypeDeleter;
using MessageUniquePtr
[[deprecated("use std::unique_ptr<PublishedType, PublishedTypeDeleter>")]] =
std::unique_ptr<PublishedType, PublishedTypeDeleter>;
using MessageSharedPtr
[[deprecated("use std::shared_ptr<const PublishedType>")]] =
std::shared_ptr<const PublishedType>;
using BufferSharedPtr = typename rclcpp::experimental::buffers::IntraProcessBuffer<
ROSMessageType,
ROSMessageTypeAllocator,
@@ -128,8 +112,8 @@ public:
*
* \param[in] node_base NodeBaseInterface pointer that is used in part of the setup.
* \param[in] topic Name of the topic to publish to.
* \param[in] qos QoS profile for Subcription.
* \param[in] options Options for the subscription.
* \param[in] qos QoS profile for the publisher.
* \param[in] options Options for the publisher.
*/
Publisher(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
@@ -159,34 +143,34 @@ public:
post_init_setup(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const std::string & topic,
const rclcpp::QoS & qos,
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
[[maybe_unused]] const rclcpp::QoS & qos,
[[maybe_unused]] const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
{
// Topic is unused for now.
(void)topic;
(void)options;
// If needed, setup intra process communication.
if (rclcpp::detail::resolve_use_intra_process(options_, *node_base)) {
auto context = node_base->get_context();
// Get the intra process manager instance for this context.
auto ipm = context->get_sub_context<rclcpp::experimental::IntraProcessManager>();
// Register the publisher with the intra process manager.
if (qos.history() != rclcpp::HistoryPolicy::KeepLast) {
// Check if the QoS is compatible with intra-process.
auto qos_profile = get_actual_qos();
if (qos_profile.history() != rclcpp::HistoryPolicy::KeepLast) {
throw std::invalid_argument(
"intraprocess communication allowed only with keep last history qos policy");
"intraprocess communication on topic '" + topic +
"' allowed only with keep last history qos policy");
}
if (qos.depth() == 0) {
if (qos_profile.depth() == 0) {
throw std::invalid_argument(
"intraprocess communication is not allowed with a zero qos history depth value");
"intraprocess communication on topic '" + topic +
"' is not allowed with a zero qos history depth value");
}
if (qos.durability() == rclcpp::DurabilityPolicy::TransientLocal) {
if (qos_profile.durability() == rclcpp::DurabilityPolicy::TransientLocal) {
buffer_ = rclcpp::experimental::create_intra_process_buffer<
ROSMessageType, ROSMessageTypeAllocator, ROSMessageTypeDeleter>(
rclcpp::detail::resolve_intra_process_buffer_type(options_.intra_process_buffer_type),
qos,
qos_profile,
std::make_shared<ROSMessageTypeAllocator>(ros_message_type_allocator_));
}
// Register the publisher with the intra process manager.
uint64_t intra_process_publisher_id = ipm->add_publisher(this->shared_from_this(), buffer_);
this->setup_intra_process(
intra_process_publisher_id,
@@ -203,7 +187,7 @@ public:
* the loaned message will be directly allocated in the middleware.
* If not, the message allocator of this rclcpp::Publisher instance is being used.
*
* With a call to \sa `publish` the LoanedMessage instance is being returned to the middleware
* With a call to `publish` the LoanedMessage instance is being returned to the middleware
* or free'd accordingly to the allocator.
* If the message is not being published but processed differently, the destructor of this
* class will either return the message to the middleware or deallocate it via the internal
@@ -248,8 +232,12 @@ public:
// interprocess publish, resulting in lower publish-to-subscribe latency.
// It's not possible to do that with an unique_ptr,
// as do_intra_process_publish takes the ownership of the message.
// When durability is set to TransientLocal (i.e. there is a buffer),
// inter process publish should always take place to ensure
// late joiners receive past data.
bool inter_process_publish_needed =
get_subscription_count() > get_intra_process_subscription_count();
get_subscription_count() > get_intra_process_subscription_count() || buffer_;
if (inter_process_publish_needed) {
auto shared_msg =
@@ -326,8 +314,11 @@ public:
return;
}
// When durability is set to TransientLocal (i.e. there is a buffer),
// inter process publish should always take place to ensure
// late joiners receive past data.
bool inter_process_publish_needed =
get_subscription_count() > get_intra_process_subscription_count();
get_subscription_count() > get_intra_process_subscription_count() || buffer_;
if (inter_process_publish_needed) {
auto ros_msg_ptr = std::make_shared<ROSMessageType>();
@@ -423,13 +414,6 @@ public:
}
}
[[deprecated("use get_published_type_allocator() or get_ros_message_type_allocator() instead")]]
std::shared_ptr<PublishedTypeAllocator>
get_allocator() const
{
return std::make_shared<PublishedTypeAllocator>(published_type_allocator_);
}
PublishedTypeAllocator
get_published_type_allocator() const
{
@@ -590,6 +574,13 @@ protected:
std::unique_ptr<PublishedType, PublishedTypeDeleter>
duplicate_type_adapt_message_as_unique_ptr(const PublishedType & msg)
{
/// Assert that the published type has no overloaded operator new since this leads to
/// new/delete mismatch (see https://github.com/ros2/rclcpp/issues/2951)
static_assert(!detail::has_overloaded_operator_new_v<PublishedType>,
"When publishing by value (i.e. when calling publish(const T& msg)), the published "
"message type must not have an overloaded operator new. In this case, please use the "
"publish(std::unique_ptr<T> msg) method instead.");
auto ptr = PublishedTypeAllocatorTraits::allocate(published_type_allocator_, 1);
PublishedTypeAllocatorTraits::construct(published_type_allocator_, ptr, msg);
return std::unique_ptr<PublishedType, PublishedTypeDeleter>(ptr, published_type_deleter_);

View File

@@ -146,10 +146,18 @@ public:
QoS(size_t history_depth); // NOLINT(runtime/explicit): conversion constructor
/// Return the rmw qos profile.
/**
* The profile consists of various QoS policies such as history, reliability, and durability.
* Use the corresponding getter functions to retrieve individual policies.
*/
rmw_qos_profile_t &
get_rmw_qos_profile();
/// Return the rmw qos profile.
/**
* The profile consists of various QoS policies such as history, reliability, and durability.
* Use the corresponding getter functions to retrieve individual policies.
*/
const rmw_qos_profile_t &
get_rmw_qos_profile() const;
@@ -475,7 +483,7 @@ public:
explicit
RosoutQoS(
const QoSInitialization & rosout_qos_initialization = (
QoSInitialization::from_rmw(rcl_qos_profile_rosout_default)
QoSInitialization::from_rmw(rmw_qos_profile_rosout_default)
));
};

View File

@@ -39,10 +39,6 @@ public:
RCLCPP_PUBLIC
virtual bool sleep() = 0;
[[deprecated("use get_type() instead")]]
RCLCPP_PUBLIC
virtual bool is_steady() const = 0;
RCLCPP_PUBLIC
virtual rcl_clock_type_t get_type() const = 0;
@@ -54,82 +50,6 @@ using std::chrono::duration;
using std::chrono::duration_cast;
using std::chrono::nanoseconds;
template<class Clock = std::chrono::high_resolution_clock>
class [[deprecated("use rclcpp::Rate class instead of GenericRate")]] GenericRate : public RateBase
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(GenericRate)
explicit GenericRate(double rate)
: period_(duration_cast<nanoseconds>(duration<double>(1.0 / rate))), last_interval_(Clock::now())
{}
explicit GenericRate(std::chrono::nanoseconds period)
: period_(period), last_interval_(Clock::now())
{}
virtual bool
sleep()
{
// Time coming into sleep
auto now = Clock::now();
// Time of next interval
auto next_interval = last_interval_ + period_;
// Detect backwards time flow
if (now < last_interval_) {
// Best thing to do is to set the next_interval to now + period
next_interval = now + period_;
}
// Calculate the time to sleep
auto time_to_sleep = next_interval - now;
// Update the interval
last_interval_ += period_;
// If the time_to_sleep is negative or zero, don't sleep
if (time_to_sleep <= std::chrono::seconds(0)) {
// If an entire cycle was missed then reset next interval.
// This might happen if the loop took more than a cycle.
// Or if time jumps forward.
if (now > next_interval + period_) {
last_interval_ = now + period_;
}
// Either way do not sleep and return false
return false;
}
// Sleep (will get interrupted by ctrl-c, may not sleep full time)
rclcpp::sleep_for(time_to_sleep);
return true;
}
[[deprecated("use get_type() instead")]]
virtual bool
is_steady() const
{
return Clock::is_steady;
}
virtual rcl_clock_type_t get_type() const
{
return Clock::is_steady ? RCL_STEADY_TIME : RCL_SYSTEM_TIME;
}
virtual void
reset()
{
last_interval_ = Clock::now();
}
std::chrono::nanoseconds period() const
{
return period_;
}
private:
RCLCPP_DISABLE_COPY(GenericRate)
std::chrono::nanoseconds period_;
using ClockDurationNano = std::chrono::duration<typename Clock::rep, std::nano>;
std::chrono::time_point<Clock, ClockDurationNano> last_interval_;
};
class Rate : public RateBase
{
public:
@@ -149,11 +69,6 @@ public:
virtual bool
sleep();
[[deprecated("use get_type() instead")]]
RCLCPP_PUBLIC
virtual bool
is_steady() const;
RCLCPP_PUBLIC
virtual rcl_clock_type_t
get_type() const;

View File

@@ -68,8 +68,6 @@
*
* - Executors (responsible for execution of callbacks through a blocking spin):
* - rclcpp::spin()
* - rclcpp::spin_some()
* - rclcpp::spin_until_future_complete()
* - rclcpp::executors::SingleThreadedExecutor
* - rclcpp::executors::SingleThreadedExecutor::add_node()
* - rclcpp::executors::SingleThreadedExecutor::spin()

View File

@@ -307,7 +307,7 @@ public:
* \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] any_callback User defined callback to call when a client request is received.
* \param[in] service_options options for the subscription.
* \param[in] service_options options for the service.
*/
Service(
std::shared_ptr<rcl_node_t> node_handle,
@@ -504,6 +504,9 @@ public:
* \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(

View File

@@ -201,6 +201,7 @@ public:
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't add subscription to wait set: %s", rcl_get_error_string().str);
rcl_reset_error();
return false;
}
}
@@ -210,6 +211,7 @@ public:
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't add client to wait set: %s", rcl_get_error_string().str);
rcl_reset_error();
return false;
}
}
@@ -219,6 +221,7 @@ public:
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't add service to wait set: %s", rcl_get_error_string().str);
rcl_reset_error();
return false;
}
}
@@ -228,6 +231,7 @@ public:
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't add timer to wait set: %s", rcl_get_error_string().str);
rcl_reset_error();
return false;
}
}

View File

@@ -114,9 +114,9 @@ public:
* all references.
* \param[in] msg Shared pointer to the message to return.
*/
void return_message(std::shared_ptr<MessageT> & msg)
void return_message([[maybe_unused]] std::shared_ptr<MessageT> & msg)
{
(void)msg;
// This function is intentionally left empty.
}
protected:

View File

@@ -90,18 +90,6 @@ public:
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
using MessageAllocatorTraits [[deprecated("use ROSMessageTypeAllocatorTraits")]] =
ROSMessageTypeAllocatorTraits;
using MessageAllocator [[deprecated("use ROSMessageTypeAllocator")]] =
ROSMessageTypeAllocator;
using MessageDeleter [[deprecated("use ROSMessageTypeDeleter")]] =
ROSMessageTypeDeleter;
using ConstMessageSharedPtr [[deprecated]] = std::shared_ptr<const ROSMessageType>;
using MessageUniquePtr
[[deprecated("use std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> instead")]] =
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>;
private:
using SubscriptionTopicStatisticsSharedPtr =
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics>;
@@ -159,11 +147,13 @@ public:
auto qos_profile = get_actual_qos();
if (qos_profile.history() != rclcpp::HistoryPolicy::KeepLast) {
throw std::invalid_argument(
"intraprocess communication allowed only with keep last history qos policy");
"intraprocess communication on topic '" + topic_name +
"' allowed only with keep last history qos policy");
}
if (qos_profile.depth() == 0) {
throw std::invalid_argument(
"intraprocess communication is not allowed with 0 depth qos policy");
"intraprocess communication on topic '" + topic_name +
"' is not allowed with 0 depth qos policy");
}
using SubscriptionIntraProcessT = rclcpp::experimental::SubscriptionIntraProcess<
@@ -219,13 +209,11 @@ public:
/// Called after construction to continue setup that requires shared_from_this().
void
post_init_setup(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const rclcpp::QoS & qos,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options)
[[maybe_unused]] rclcpp::node_interfaces::NodeBaseInterface * node_base,
[[maybe_unused]] const rclcpp::QoS & qos,
[[maybe_unused]] const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options)
{
(void)node_base;
(void)qos;
(void)options;
// This function is intentionally left empty.
}
/// Take the next message from the inter-process subscription.
@@ -432,20 +420,17 @@ public:
void
return_dynamic_message(
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message) override
[[maybe_unused]] rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message) override
{
(void) message;
throw rclcpp::exceptions::UnimplementedError(
"return_dynamic_message is not implemented for Subscription");
}
void
handle_dynamic_message(
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
const rclcpp::MessageInfo & message_info) override
[[maybe_unused]] const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
[[maybe_unused]] const rclcpp::MessageInfo & message_info) override
{
(void) message;
(void) message_info;
throw rclcpp::exceptions::UnimplementedError(
"handle_dynamic_message is not implemented for Subscription");
}

View File

@@ -20,8 +20,8 @@
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
#include <utility>
#include <vector>
#include "rcl/event_callback.h"
#include "rcl/subscription.h"

View File

@@ -80,7 +80,8 @@ struct SubscriptionOptionsBase
// An optional QoS which can provide topic_statistics with a stable QoS separate from
// the subscription's current QoS settings which could be unstable.
rclcpp::QoS qos = SystemDefaultsQoS();
// Explicitly set the enough depth to avoid missing the statistics messages.
rclcpp::QoS qos = SystemDefaultsQoS().keep_last(10);
};
TopicStatisticsOptions topic_stats_options;

View File

@@ -33,12 +33,11 @@ class Time
public:
/// Time constructor
/**
* Initializes the time values for seconds and nanoseconds individually.
* Large values for nanoseconds are wrapped automatically with the remainder added to seconds.
* Both inputs must be integers.
* Indicates a specific point in time, relative to a clock's 0 point (its epoch).
* The total time since the epoch is given by seconds + nanoseconds.
*
* \param seconds part of the time in seconds since time epoch
* \param nanoseconds part of the time in nanoseconds since time epoch
* \param seconds the seconds component, valid only if positive
* \param nanoseconds the nanoseconds component, to be added to the seconds component
* \param clock_type clock type
* \throws std::runtime_error if seconds are negative
*/
@@ -47,8 +46,9 @@ public:
/// Time constructor
/**
* \param nanoseconds since time epoch
* \param nanoseconds the total time since the epoch in nanoseconds
* \param clock_type clock type
* \throws std::runtime_error if nanoseconds are negative
*/
RCLCPP_PUBLIC
explicit Time(int64_t nanoseconds = 0, rcl_clock_type_t clock_type = RCL_SYSTEM_TIME);
@@ -189,7 +189,7 @@ public:
/// Get the nanoseconds since epoch
/**
* \return the nanoseconds since epoch as a rcl_time_point_value_t structure.
* \return the total time since the epoch in nanoseconds, as a rcl_time_point_value_t structure.
*/
RCLCPP_PUBLIC
rcl_time_point_value_t
@@ -208,7 +208,7 @@ public:
* \warning Depending on sizeof(double) there could be significant precision loss.
* When an exact time is required use nanoseconds() instead.
*
* \return the seconds since epoch as a floating point number.
* \return the total time since the epoch in seconds, as a floating point number.
*/
RCLCPP_PUBLIC
double

View File

@@ -172,12 +172,11 @@ private:
{
auto received_message_age = std::make_unique<ReceivedMessageAge>();
received_message_age->Start();
subscriber_statistics_collectors_.emplace_back(std::move(received_message_age));
auto received_message_period = std::make_unique<ReceivedMessagePeriod>();
received_message_period->Start();
{
std::lock_guard<std::mutex> lock(mutex_);
subscriber_statistics_collectors_.emplace_back(std::move(received_message_age));
subscriber_statistics_collectors_.emplace_back(std::move(received_message_period));
}

View File

@@ -16,6 +16,7 @@
#define RCLCPP__TYPE_ADAPTER_HPP_
#include <type_traits>
#include <new>
namespace rclcpp
{
@@ -128,6 +129,24 @@ struct assert_type_pair_is_specialized_type_adapter
"No type adapter for this custom type/ros message type pair");
};
template<typename, typename = void>
struct has_overloaded_operator_new : std::false_type {};
template<typename T>
struct has_overloaded_operator_new<T, std::void_t<
decltype(T::operator new(std::size_t()))
>>: std::true_type {};
template<typename, typename = void>
struct has_overloaded_aligned_operator_new : std::false_type {};
template<typename T>
struct has_overloaded_aligned_operator_new<T,
std::void_t<decltype( T::operator new(std::size_t(), std::align_val_t()) )>>
: std::true_type {};
template<typename T>
inline constexpr bool has_overloaded_operator_new_v = has_overloaded_operator_new<T>::value ||
has_overloaded_aligned_operator_new<T>::value;
} // namespace detail
/// Template metafunction that can make the type being adapted explicit.

View File

@@ -21,6 +21,7 @@
#include <tuple>
#include "rcpputils/shared_library.hpp"
#include "rosidl_runtime_cpp/action_type_support_decl.hpp"
#include "rosidl_runtime_cpp/message_type_support_decl.hpp"
#include "rosidl_runtime_cpp/service_type_support_decl.hpp"
@@ -28,45 +29,48 @@
namespace rclcpp
{
/// Load the type support library for the given type.
/**
* \param[in] type The topic type, e.g. "std_msgs/msg/String"
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
* \return A shared library
*/
/// \brief Extract the package name, middle module, and type name from a full type string.
/// \details This function takes a full type string (e.g., "std_msgs/msg/String") and extracts
/// the package name, middle module (if any), and type name. The middle module is the part
/// between the package name and the type name, which is typically used for message types.
/// For example, for "std_msgs/msg/String", it returns ("std_msgs", "msg", "String").
/// \param[in] full_type
/// \throws std::runtime_error if the input full type string is malformed or does not follow the
/// expected format.
/// \return A tuple containing the package name, middle module (if any), and type name.
RCLCPP_PUBLIC
std::tuple<std::string, std::string, std::string>
extract_type_identifier(const std::string & full_type);
/// \brief Look for the library in the ament prefix paths and return the path to the type support
/// library.
/// \param[in] package_name The name of the package containing the type support library,
/// e.g. "std_msgs".
/// \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
/// \throws std::runtime_error if the library is not found.
/// \return The path to the type support library.
RCLCPP_PUBLIC
std::string get_typesupport_library_path(
const std::string & package_name, const std::string & typesupport_identifier);
/// \brief Load the type support library for the given type.
/// \param[in] type The topic type, e.g. "std_msgs/msg/String"
/// \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
/// \throws std::runtime_error if the library is not found or cannot be loaded.
/// \return A shared library
RCLCPP_PUBLIC
std::shared_ptr<rcpputils::SharedLibrary>
get_typesupport_library(const std::string & type, const std::string & typesupport_identifier);
/// Extract the type support handle from the library.
/**
* The library needs to match the topic type. The shared library must stay loaded for the lifetime of the result.
*
* \deprecated Use get_message_typesupport_handle() instead
*
* \param[in] type The topic type, e.g. "std_msgs/msg/String"
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
* \param[in] library The shared type support library
* \return A type support handle
*/
[[deprecated("Use `get_message_typesupport_handle` instead")]]
RCLCPP_PUBLIC
const rosidl_message_type_support_t *
get_typesupport_handle(
const std::string & type,
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library);
/// Extract the message type support handle from the library.
/**
* The library needs to match the topic type. The shared library must stay loaded for the lifetime of the result.
*
* \param[in] type The topic type, e.g. "std_msgs/msg/String"
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
* \param[in] library The shared type support library
* \throws std::runtime_error if the symbol of type not found in the library.
* \return A message type support handle
*/
/// \brief Extracts the message type support handle from the library.
/// \note The library needs to match the topic type. The shared library must stay loaded for the
/// lifetime of the result.
/// \param[in] type The topic type, e.g. "std_msgs/msg/String"
/// \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
/// \param[in] library The shared type support library
/// \throws std::runtime_error if the symbol of type not found in the library.
/// \return A message type support handle
RCLCPP_PUBLIC
const rosidl_message_type_support_t *
get_message_typesupport_handle(
@@ -74,16 +78,14 @@ get_message_typesupport_handle(
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library);
/// Extract the service type support handle from the library.
/**
* The library needs to match the topic type. The shared library must stay loaded for the lifetime of the result.
*
* \param[in] type The service type, e.g. "std_srvs/srv/Empty"
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
* \param[in] library The shared type support library
* \throws std::runtime_error if the symbol of type not found in the library.
* \return A service type support handle
*/
/// \brief Extracts the service type support handle from the library.
/// \note The library needs to match the service type. The shared library must stay loaded for the
/// lifetime of the result.
/// \param[in] type The service type, e.g. "std_srvs/srv/Empty"
/// \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
/// \param[in] library The shared type support library
/// \throws std::runtime_error if the symbol of type not found in the library.
/// \return A service type support handle
RCLCPP_PUBLIC
const rosidl_service_type_support_t *
get_service_typesupport_handle(
@@ -91,6 +93,21 @@ get_service_typesupport_handle(
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library);
/// \brief Extracts the action type support handle from the library.
/// \note The library needs to match the action type. The shared library must stay loaded for the
/// lifetime of the result.
/// \param[in] type The action type, e.g. "example_interfaces/action/Fibonacci"
/// \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
/// \param[in] library The shared type support library
/// \throws std::runtime_error if the symbol of type not found in the library.
/// \return A action type support handle
RCLCPP_PUBLIC
const rosidl_action_type_support_t *
get_action_typesupport_handle(
const std::string & type,
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library);
} // namespace rclcpp
#endif // RCLCPP__TYPESUPPORT_HELPERS_HPP_

View File

@@ -15,6 +15,7 @@
#ifndef RCLCPP__WAIT_FOR_MESSAGE_HPP_
#define RCLCPP__WAIT_FOR_MESSAGE_HPP_
#include <future>
#include <memory>
#include <string>
@@ -23,6 +24,7 @@
#include "rclcpp/node.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/wait_set.hpp"
#include "rclcpp/qos.hpp"
namespace rclcpp
{
@@ -79,10 +81,11 @@ bool wait_for_message(
/**
* Wait for the next incoming message to arrive on a specified topic before the specified timeout.
*
* \param[out] out is the message to be filled when a new message is arriving.
* \param[out] out is the message to be filled when a new message is arriving
* \param[in] node the node pointer to initialize the subscription on.
* \param[in] topic the topic to wait for messages.
* \param[in] time_to_wait parameter specifying the timeout before returning.
* \param[in] qos parameter specifying QoS settings for the subscription.
* \return true if a message was successfully received, false if message could not
* be obtained or shutdown was triggered asynchronously on the context.
*/
@@ -91,9 +94,10 @@ bool wait_for_message(
MsgT & out,
rclcpp::Node::SharedPtr node,
const std::string & topic,
std::chrono::duration<Rep, Period> time_to_wait = std::chrono::duration<Rep, Period>(-1))
std::chrono::duration<Rep, Period> time_to_wait = std::chrono::duration<Rep, Period>(-1),
const rclcpp::QoS & qos = rclcpp::SystemDefaultsQoS())
{
auto sub = node->create_subscription<MsgT>(topic, 1, [](const std::shared_ptr<const MsgT>) {});
auto sub = node->create_subscription<MsgT>(topic, qos, [](const std::shared_ptr<const MsgT>) {});
return wait_for_message<MsgT, Rep, Period>(
out, sub, node->get_node_options().context(), time_to_wait);
}

View File

@@ -176,7 +176,9 @@ public:
for (; ii < wait_set.size_of_timers(); ++ii) {
if (rcl_wait_set.timers[ii] != nullptr) {
ret = wait_set.timers(ii);
break;
if (ret) {
break;
}
}
}
}
@@ -217,7 +219,9 @@ public:
if (rcl_wait_set.subscriptions[ii] != nullptr) {
ret = wait_set.subscriptions(ii);
rcl_wait_set.subscriptions[ii] = nullptr;
break;
if (ret) {
break;
}
}
}
}
@@ -237,7 +241,9 @@ public:
if (rcl_wait_set.services[ii] != nullptr) {
ret = wait_set.services(ii);
rcl_wait_set.services[ii] = nullptr;
break;
if (ret) {
break;
}
}
}
}
@@ -257,7 +263,9 @@ public:
if (rcl_wait_set.clients[ii] != nullptr) {
ret = wait_set.clients(ii);
rcl_wait_set.clients[ii] = nullptr;
break;
if (ret) {
break;
}
}
}
}

View File

@@ -216,6 +216,11 @@ public:
shared_waitables_
);
if (this->needs_pruning_) {
this->storage_prune_deleted_entities();
this->needs_pruning_ = false;
}
this->storage_release_ownerships();
}
@@ -455,59 +460,60 @@ public:
size_t size_of_subscriptions() const
{
return shared_subscriptions_.size();
return subscriptions_.size();
}
size_t size_of_timers() const
{
return shared_timers_.size();
return timers_.size();
}
size_t size_of_clients() const
{
return shared_clients_.size();
return clients_.size();
}
size_t size_of_services() const
{
return shared_services_.size();
return services_.size();
}
size_t size_of_waitables() const
{
return shared_waitables_.size();
return waitables_.size();
}
std::shared_ptr<rclcpp::SubscriptionBase>
subscriptions(size_t ii) const
{
return shared_subscriptions_[ii].subscription;
return subscriptions_[ii].lock();
}
std::shared_ptr<rclcpp::TimerBase>
timers(size_t ii) const
{
return shared_timers_[ii];
return timers_[ii].lock();
}
std::shared_ptr<rclcpp::ClientBase>
clients(size_t ii) const
{
return shared_clients_[ii];
return clients_[ii].lock();
}
std::shared_ptr<rclcpp::ServiceBase>
services(size_t ii) const
{
return shared_services_[ii];
return services_[ii].lock();
}
std::shared_ptr<rclcpp::Waitable>
waitables(size_t ii) const
{
return shared_waitables_[ii].waitable;
return waitables_[ii].lock();
}
private:
size_t ownership_reference_counter_ = 0;
SequenceOfWeakSubscriptions subscriptions_;

View File

@@ -160,6 +160,15 @@ public:
services_,
waitables_
);
if(this->needs_pruning_) {
// we need to throw here, as the indexing of the rcl_waitset is broken,
// in case of invalid entries
throw std::runtime_error(
"StaticStorage::storage_rebuild_rcl_wait_set(): entity weak_ptr "
"unexpectedly expired in static entity storage");
}
}
// storage_add_subscription() explicitly not declared here

View File

@@ -734,8 +734,6 @@ private:
wait_result_dirty_ = false;
// this method comes from the SynchronizationPolicy
this->sync_wait_result_acquire();
// this method comes from the StoragePolicy
this->storage_acquire_ownerships();
}
/// Called by the WaitResult's destructor to release resources.
@@ -752,8 +750,6 @@ private:
}
wait_result_holding_ = false;
wait_result_dirty_ = false;
// this method comes from the StoragePolicy
this->storage_release_ownerships();
// this method comes from the SynchronizationPolicy
this->sync_wait_result_release();
}

View File

@@ -18,6 +18,7 @@
#include <atomic>
#include <functional>
#include <memory>
#include <vector>
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -27,6 +28,8 @@
namespace rclcpp
{
class TimerBase;
class Waitable
{
public:
@@ -101,23 +104,6 @@ public:
size_t
get_number_of_ready_guard_conditions();
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Woverloaded-virtual"
#endif
/// Deprecated.
/**
* \sa add_to_wait_set(rcl_wait_set_t &)
*/
[[deprecated("Use add_to_wait_set(rcl_wait_set_t & wait_set) signature")]]
RCLCPP_PUBLIC
virtual
void
add_to_wait_set(rcl_wait_set_t * wait_set);
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
/// Add the Waitable to a wait set.
/**
* \param[in] wait_set A handle to the wait set to add the Waitable to.
@@ -126,24 +112,7 @@ public:
RCLCPP_PUBLIC
virtual
void
add_to_wait_set(rcl_wait_set_t & wait_set);
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Woverloaded-virtual"
#endif
/// Deprecated.
/**
* \sa is_ready(const rcl_wait_set_t &)
*/
[[deprecated("Use is_ready(const rcl_wait_set_t & wait_set) signature")]]
RCLCPP_PUBLIC
virtual
bool
is_ready(rcl_wait_set_t * wait_set);
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
add_to_wait_set(rcl_wait_set_t & wait_set) = 0;
/// Check if the Waitable is ready.
/**
@@ -158,7 +127,7 @@ public:
RCLCPP_PUBLIC
virtual
bool
is_ready(const rcl_wait_set_t & wait_set);
is_ready(const rcl_wait_set_t & wait_set) = 0;
/// Take the data so that it can be consumed with `execute`.
/**
@@ -210,24 +179,7 @@ public:
RCLCPP_PUBLIC
virtual
std::shared_ptr<void>
take_data_by_entity_id(size_t id);
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Woverloaded-virtual"
#endif
/// Deprecated.
/**
* \sa execute(const std::shared_ptr<void> &)
*/
[[deprecated("Use execute(const std::shared_ptr<void> & data) signature")]]
RCLCPP_PUBLIC
virtual
void
execute(std::shared_ptr<void> & data);
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
take_data_by_entity_id(size_t id) = 0;
/// Execute data that is passed in.
/**
@@ -254,7 +206,7 @@ public:
RCLCPP_PUBLIC
virtual
void
execute(const std::shared_ptr<void> & data);
execute(const std::shared_ptr<void> & data) = 0;
/// Exchange the "in use by wait set" state for this timer.
/**
@@ -297,7 +249,7 @@ public:
RCLCPP_PUBLIC
virtual
void
set_on_ready_callback(std::function<void(size_t, int)> callback);
set_on_ready_callback(std::function<void(size_t, int)> callback) = 0;
/// Unset any callback registered via set_on_ready_callback.
/**
@@ -307,7 +259,18 @@ public:
RCLCPP_PUBLIC
virtual
void
clear_on_ready_callback();
clear_on_ready_callback() = 0;
/// Returns all timers used by this waitable
/**
* Must return all timers used within the waitable.
* Note, it is not supported, that timers are added
* or removed over the lifetime of the waitable.
*/
RCLCPP_PUBLIC
virtual
std::vector<std::shared_ptr<rclcpp::TimerBase>>
get_timers() const = 0;
private:
std::atomic<bool> in_use_by_wait_set_{false};

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp</name>
<version>28.1.5</version>
<version>30.1.3</version>
<description>The ROS client library in C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
@@ -17,6 +17,7 @@
<buildtool_depend>ament_cmake_ros</buildtool_depend>
<buildtool_depend>ament_cmake_gen_version_h</buildtool_depend>
<buildtool_depend>python3</buildtool_depend>
<buildtool_depend>python3-empy</buildtool_depend>
<build_depend>ament_index_cpp</build_depend>
<build_depend>builtin_interfaces</build_depend>

View File

@@ -1,165 +0,0 @@
// generated from rclcpp/resource/logging.hpp.em
// 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"
#include "rclcpp/utilities.hpp"
// 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_FIRST_ARG(N, ...) N
#define RCLCPP_ALL_BUT_FIRST_ARGS(N, ...) __VA_ARGS__
/**
* \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
@{
from collections import OrderedDict
from copy import deepcopy
from rcutils.logging import feature_combinations
from rcutils.logging import get_suffix_from_features
from rcutils.logging import severities
from rcutils.logging import throttle_args
from rcutils.logging import throttle_params
throttle_args['condition_before'] = 'RCUTILS_LOG_CONDITION_THROTTLE_BEFORE(clock, duration)'
del throttle_params['get_time_point_value']
throttle_params['clock'] = 'rclcpp::Clock that will be used to get the time point.'
throttle_params.move_to_end('clock', last=False)
rclcpp_feature_combinations = OrderedDict()
for combinations, feature in feature_combinations.items():
# skip feature combinations using 'named'
if 'named' in combinations:
continue
rclcpp_feature_combinations[combinations] = feature
# add a stream variant for each available feature combination
stream_arg = 'stream_arg'
for combinations, feature in list(rclcpp_feature_combinations.items()):
combinations = ('stream', ) + combinations
feature = deepcopy(feature)
feature.params[stream_arg] = 'The argument << into a stringstream'
rclcpp_feature_combinations[combinations] = feature
def get_rclcpp_suffix_from_features(features):
suffix = get_suffix_from_features(features)
if 'stream' in features:
suffix = '_STREAM' + suffix
return suffix
}@
@[for severity in severities]@
/** @@name Logging macros for severity @(severity).
*/
///@@{
#if (RCLCPP_LOG_MIN_SEVERITY > RCLCPP_LOG_MIN_SEVERITY_@(severity))
// empty logging macros for severity @(severity) when being disabled at compile time
@[ for feature_combination in rclcpp_feature_combinations.keys()]@
@{suffix = get_rclcpp_suffix_from_features(feature_combination)}@
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
#define RCLCPP_@(severity)@(suffix)(...)
@[ end for]@
#else
@[ for feature_combination in rclcpp_feature_combinations.keys()]@
@{suffix = get_rclcpp_suffix_from_features(feature_combination)}@
// The RCLCPP_@(severity)@(suffix) macro is surrounded by do { .. } while (0)
// to implement the standard C macro idiom to make the macro safe in all
// contexts; see http://c-faq.com/cpp/multistmt.html for more information.
/**
* \def RCLCPP_@(severity)@(suffix)
* Log a message with severity @(severity)@
@[ if rclcpp_feature_combinations[feature_combination].doc_lines]@
with the following conditions:
@[ else]@
.
@[ end if]@
@[ for doc_line in rclcpp_feature_combinations[feature_combination].doc_lines]@
* @(doc_line)
@[ end for]@
* \param logger The `rclcpp::Logger` to use
@[ for param_name, doc_line in rclcpp_feature_combinations[feature_combination].params.items()]@
* \param @(param_name) @(doc_line)
@[ end for]@
@[ if 'stream' not in feature_combination]@
* \param ... The format string, followed by the variable arguments for the format string.
@[ end if]@
*/
@{params = rclcpp_feature_combinations[feature_combination].params.keys()}@
#define RCLCPP_@(severity)@(suffix)(logger@(''.join([', ' + p for p in params]))@
@[ if 'stream' not in feature_combination]@
, ...@
@[ end if]@
) \
do { \
static_assert( \
::std::is_same<typename std::remove_cv_t<typename std::remove_reference_t<decltype(logger)>>, \
typename ::rclcpp::Logger>::value, \
"First argument to logging macros must be an rclcpp::Logger"); \
@[ if 'throttle' in feature_combination]@ \
auto get_time_point = [&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_@(severity)@(suffix) could not get current time stamp\n"); \
return RCUTILS_RET_ERROR; \
} \
return RCUTILS_RET_OK; \
}; \
@[ end if] \
@[ if 'stream' in feature_combination]@
std::stringstream rclcpp_stream_ss_; \
rclcpp_stream_ss_ << @(stream_arg); \
@[ end if]@
RCUTILS_LOG_@(severity)@(get_suffix_from_features(feature_combination))_NAMED( \
@{params = ['get_time_point' if p == 'clock' and 'throttle' in feature_combination else p for p in params]}@
@[ if params]@
@(''.join([' ' + p + ', \\\n' for p in params if p != stream_arg]))@
@[ end if]@
(logger).get_name(), \
@[ if 'stream' not in feature_combination]@
__VA_ARGS__); \
@[ else]@
"%s", rclcpp_stream_ss_.str().c_str()); \
@[ end if]@
} while (0)
@[ end for]@
#endif
///@@}
@[end for]@
#endif // RCLCPP__LOGGING_HPP_

View File

@@ -83,16 +83,6 @@ Clock::now() const
return now;
}
void
Clock::cancel_sleep_or_wait()
{
{
std::unique_lock lock(impl_->wait_mutex_);
impl_->stop_sleeping_ = true;
}
impl_->cv_.notify_one();
}
bool
Clock::sleep_until(
Time until,
@@ -367,4 +357,245 @@ Clock::create_jump_callback(
// *INDENT-ON*
}
class ClockWaiter::ClockWaiterImpl
{
private:
std::condition_variable cv_;
rclcpp::Clock::SharedPtr clock_;
bool time_source_changed_ = false;
std::function<void(const rcl_time_jump_t &)> post_time_jump_callback;
bool
wait_until_system_time(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred)
{
auto system_time = std::chrono::system_clock::time_point(
// Cast because system clock resolution is too big for nanoseconds on some systems
std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::nanoseconds(abs_time.nanoseconds())));
return cv_.wait_until(lock, system_time, pred);
}
bool
wait_until_steady_time(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred)
{
// Synchronize because RCL steady clock epoch might differ from chrono::steady_clock epoch
const rclcpp::Time rcl_entry = clock_->now();
const std::chrono::steady_clock::time_point chrono_entry = std::chrono::steady_clock::now();
const rclcpp::Duration delta_t = abs_time - rcl_entry;
const std::chrono::steady_clock::time_point chrono_until =
chrono_entry + std::chrono::nanoseconds(delta_t.nanoseconds());
return cv_.wait_until(lock, chrono_until, pred);
}
bool
wait_until_ros_time(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred)
{
// Install jump handler for any amount of time change, for two purposes:
// - if ROS time is active, check if time reached on each new clock sample
// - Trigger via on_clock_change to detect if time source changes, to invalidate sleep
rcl_jump_threshold_t threshold;
threshold.on_clock_change = true;
// 0 is disable, so -1 and 1 are smallest possible time changes
threshold.min_backward.nanoseconds = -1;
threshold.min_forward.nanoseconds = 1;
time_source_changed_ = false;
post_time_jump_callback = [this, &lock] (const rcl_time_jump_t & jump)
{
if (jump.clock_change != RCL_ROS_TIME_NO_CHANGE) {
std::lock_guard<std::mutex> lk(*lock.mutex());
time_source_changed_ = true;
}
cv_.notify_one();
};
// Note this is a trade-off. Adding the callback for every call
// is expensive for high frequency calls. For low frequency waits
// its more overhead to have the callback being called all the time.
// As we expect the use case to be low frequency calls to wait_until
// with relative big pauses between the calls, we install it on demand.
auto clock_handler = clock_->create_jump_callback(
nullptr,
post_time_jump_callback,
threshold);
if (!clock_->ros_time_is_active()) {
auto system_time = std::chrono::system_clock::time_point(
// Cast because system clock resolution is too big for nanoseconds on some systems
std::chrono::duration_cast<std::chrono::system_clock::duration>(
std::chrono::nanoseconds(abs_time.nanoseconds())));
return cv_.wait_until(lock, system_time, [this, &pred] () {
return time_source_changed_ || pred();
});
}
// RCL_ROS_TIME with ros_time_is_active.
// Just wait without "until" because installed
// jump callbacks wake the cv on every new sample.
cv_.wait(lock, [this, &pred, &abs_time] () {
return clock_->now() >= abs_time || time_source_changed_ || pred();
});
return clock_->now() < abs_time;
}
public:
explicit ClockWaiterImpl(const rclcpp::Clock::SharedPtr & clock)
:clock_(clock)
{
}
bool
wait_until(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred)
{
switch(clock_->get_clock_type()) {
case RCL_CLOCK_UNINITIALIZED:
throw std::runtime_error("Error, wait on uninitialized clock called");
case RCL_ROS_TIME:
return wait_until_ros_time(lock, abs_time, pred);
break;
case RCL_STEADY_TIME:
return wait_until_steady_time(lock, abs_time, pred);
break;
case RCL_SYSTEM_TIME:
return wait_until_system_time(lock, abs_time, pred);
break;
}
return false;
}
void
notify_one()
{
cv_.notify_one();
}
};
ClockWaiter::ClockWaiter(const rclcpp::Clock::SharedPtr & clock)
:impl_(std::make_unique<ClockWaiterImpl>(clock))
{
}
ClockWaiter::~ClockWaiter() = default;
bool
ClockWaiter::wait_until(
std::unique_lock<std::mutex> & lock,
const rclcpp::Time & abs_time, const std::function<bool ()> & pred)
{
return impl_->wait_until(lock, abs_time, pred);
}
void
ClockWaiter::notify_one()
{
impl_->notify_one();
}
class ClockConditionalVariable::Impl
{
std::mutex pred_mutex_;
bool shutdown_ = false;
rclcpp::Context::SharedPtr context_;
rclcpp::OnShutdownCallbackHandle shutdown_cb_handle_;
ClockWaiter::UniquePtr clock_;
public:
Impl(const rclcpp::Clock::SharedPtr & clock, rclcpp::Context::SharedPtr context)
:context_(context),
clock_(std::make_unique<ClockWaiter>(clock))
{
if (!context_ || !context_->is_valid()) {
throw std::runtime_error("context cannot be slept with because it's invalid");
}
// Wake this thread if the context is shutdown
shutdown_cb_handle_ = context_->add_on_shutdown_callback(
[this]() {
{
std::unique_lock lock(pred_mutex_);
shutdown_ = true;
}
clock_->notify_one();
});
}
~Impl()
{
context_->remove_on_shutdown_callback(shutdown_cb_handle_);
}
bool
wait_until(
std::unique_lock<std::mutex> & lock, rclcpp::Time until,
const std::function<bool ()> & pred)
{
if(lock.mutex() != &pred_mutex_) {
throw std::runtime_error(
"ClockConditionalVariable::wait_until: Internal error, given lock does not use"
" mutex returned by this->mutex()");
}
clock_->wait_until(lock, until, [this, &pred] () -> bool {
return shutdown_ || pred();
});
return true;
}
void
notify_one()
{
clock_->notify_one();
}
std::mutex &
mutex()
{
return pred_mutex_;
}
};
ClockConditionalVariable::ClockConditionalVariable(
const rclcpp::Clock::SharedPtr & clock,
rclcpp::Context::SharedPtr context)
:impl_(std::make_unique<Impl>(clock, context))
{
}
ClockConditionalVariable::~ClockConditionalVariable() = default;
void
ClockConditionalVariable::notify_one()
{
impl_->notify_one();
}
bool
ClockConditionalVariable::wait_until(
std::unique_lock<std::mutex> & lock, rclcpp::Time until,
const std::function<bool ()> & pred)
{
return impl_->wait_until(lock, until, pred);
}
std::mutex &
ClockConditionalVariable::mutex()
{
return impl_->mutex();
}
} // namespace rclcpp

View File

@@ -28,7 +28,7 @@
#include "rclcpp/detail/utilities.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/graph_listener.hpp"
#include "rcutils/error_handling.h"
#include "rcutils/macros.h"
@@ -145,7 +145,8 @@ rclcpp_logging_output_handler(
Context::Context()
: rcl_context_(nullptr),
shutdown_reason_(""),
logging_mutex_(nullptr)
logging_mutex_(nullptr),
graph_listener_(nullptr)
{}
Context::~Context()
@@ -212,28 +213,27 @@ Context::init(
}
rcl_context_.reset(context, __delete_context);
if (init_options.auto_initialize_logging()) {
logging_mutex_ = get_global_logging_mutex();
std::lock_guard<std::recursive_mutex> guard(*logging_mutex_);
size_t & count = get_logging_reference_count();
if (0u == count) {
ret = rcl_logging_configure_with_output_handler(
&rcl_context_->global_arguments,
rcl_init_options_get_allocator(init_options.get_rcl_init_options()),
rclcpp_logging_output_handler);
if (RCL_RET_OK != ret) {
rcl_context_.reset();
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure logging");
}
} else {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"logging was initialized more than once");
}
++count;
}
try {
if (init_options.auto_initialize_logging()) {
logging_mutex_ = get_global_logging_mutex();
std::lock_guard<std::recursive_mutex> guard(*logging_mutex_);
size_t & count = get_logging_reference_count();
if (0u == count) {
ret = rcl_logging_configure_with_output_handler(
&rcl_context_->global_arguments,
rcl_init_options_get_allocator(init_options.get_rcl_init_options()),
rclcpp_logging_output_handler);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure logging");
}
} else {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"logging was initialized more than once");
}
++count;
}
std::vector<std::string> unparsed_ros_arguments = detail::get_unparsed_ros_arguments(
argc, argv, &(rcl_context_->global_arguments), rcl_get_default_allocator());
if (!unparsed_ros_arguments.empty()) {
@@ -244,6 +244,24 @@ Context::init(
weak_contexts_ = get_weak_contexts();
weak_contexts_->add_context(this->shared_from_this());
std::lock_guard<std::recursive_mutex> lock (on_shutdown_callbacks_mutex_);
graph_listener_ = std::make_shared<graph_listener::GraphListener>(shared_from_this());
if (!graph_listener_->is_started()) {
// Register an on_shutdown hook to shutdown the graph listener.
// This is important to ensure that the wait set is finalized before
// destruction of static objects occurs.
std::weak_ptr<rclcpp::graph_listener::GraphListener> weak_graph_listener = graph_listener_;
on_shutdown ([weak_graph_listener]() {
auto shared_graph_listener = weak_graph_listener.lock();
if(shared_graph_listener) {
shared_graph_listener->shutdown(std::nothrow);
}
});
}
} catch (const std::exception & e) {
ret = rcl_shutdown(rcl_context_.get());
rcl_context_.reset();
@@ -311,9 +329,16 @@ Context::shutdown(const std::string & reason)
// call each pre-shutdown callback
{
std::lock_guard<std::mutex> lock{pre_shutdown_callbacks_mutex_};
for (const auto & callback : pre_shutdown_callbacks_) {
(*callback)();
std::lock_guard<std::recursive_mutex> lock{pre_shutdown_callbacks_mutex_};
// callbacks may delete other callbacks during the execution,
// therefore we need to save a copy and check before execution
// if the next callback is still present
auto cpy = pre_shutdown_callbacks_;
for (const auto & callback : cpy) {
auto it = std::find(pre_shutdown_callbacks_.begin(), pre_shutdown_callbacks_.end(), callback);
if(it != pre_shutdown_callbacks_.end()) {
(*callback)();
}
}
}
@@ -326,9 +351,16 @@ Context::shutdown(const std::string & reason)
shutdown_reason_ = reason;
// call each shutdown callback
{
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
for (const auto & callback : on_shutdown_callbacks_) {
(*callback)();
std::lock_guard<std::recursive_mutex> lock(on_shutdown_callbacks_mutex_);
// callbacks may delete other callbacks during the execution,
// therefore we need to save a copy and check before execution
// if the next callback is still present
auto cpy = on_shutdown_callbacks_;
for (const auto & callback : cpy) {
auto it = std::find(on_shutdown_callbacks_.begin(), on_shutdown_callbacks_.end(), callback);
if(it != on_shutdown_callbacks_.end()) {
(*callback)();
}
}
}
@@ -399,10 +431,10 @@ Context::add_shutdown_callback(
shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
std::lock_guard<std::mutex> lock(pre_shutdown_callbacks_mutex_);
std::lock_guard<std::recursive_mutex> lock(pre_shutdown_callbacks_mutex_);
pre_shutdown_callbacks_.emplace_back(callback_shared_ptr);
} else {
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
std::lock_guard<std::recursive_mutex> lock(on_shutdown_callbacks_mutex_);
on_shutdown_callbacks_.emplace_back(callback_shared_ptr);
}
@@ -422,7 +454,7 @@ Context::remove_shutdown_callback(
}
const auto remove_callback = [&callback_shared_ptr](auto & mutex, auto & callback_vector) {
const std::lock_guard<std::mutex> lock(mutex);
const std::lock_guard<std::recursive_mutex> lock(mutex);
auto iter = callback_vector.begin();
for (; iter != callback_vector.end(); iter++) {
if ((*iter).get() == callback_shared_ptr.get()) {
@@ -463,7 +495,7 @@ std::vector<rclcpp::Context::ShutdownCallback>
Context::get_shutdown_callback() const
{
const auto get_callback_vector = [](auto & mutex, auto & callback_set) {
const std::lock_guard<std::mutex> lock(mutex);
const std::lock_guard<std::recursive_mutex> lock(mutex);
std::vector<rclcpp::Context::ShutdownCallback> callbacks;
for (auto & callback : callback_set) {
callbacks.push_back(*callback);
@@ -487,6 +519,12 @@ Context::get_rcl_context()
return rcl_context_;
}
std::shared_ptr<rclcpp::graph_listener::GraphListener>
Context::get_graph_listener()
{
return graph_listener_;
}
bool
Context::sleep_for(const std::chrono::nanoseconds & nanoseconds)
{

View File

@@ -0,0 +1,49 @@
// 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.
#include <string>
#include <memory>
#include "rclcpp/create_generic_service.hpp"
#include "rclcpp/generic_service.hpp"
namespace rclcpp
{
rclcpp::GenericService::SharedPtr
create_generic_service(
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
std::shared_ptr<node_interfaces::NodeGraphInterface> node_graph,
std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
const std::string & service_name,
const std::string & service_type,
GenericServiceCallback any_callback,
const rclcpp::QoS & qos,
rclcpp::CallbackGroup::SharedPtr group)
{
rcl_service_options_t options = rcl_service_get_default_options();
options.qos = qos.get_rmw_qos_profile();
auto srv = rclcpp::GenericService::make_shared(
node_base.get(),
node_graph,
service_name,
service_type,
any_callback,
options);
auto srv_base_ptr = std::dynamic_pointer_cast<rclcpp::ServiceBase>(srv);
node_services->add_service(srv_base_ptr, group);
return srv;
}
} // namespace rclcpp

View File

@@ -23,10 +23,9 @@ namespace detail
void
RMWImplementationSpecificPublisherPayload::modify_rmw_publisher_options(
rmw_publisher_options_t & rmw_publisher_options) const
[[maybe_unused]] rmw_publisher_options_t & rmw_publisher_options) const
{
// By default, do not mutate the rmw publisher options.
(void)rmw_publisher_options;
}
} // namespace detail

View File

@@ -23,10 +23,9 @@ namespace detail
void
RMWImplementationSpecificSubscriptionPayload::modify_rmw_subscription_options(
rmw_subscription_options_t & rmw_subscription_options) const
[[maybe_unused]] rmw_subscription_options_t & rmw_subscription_options) const
{
// By default, do not mutate the rmw subscription options.
(void)rmw_subscription_options;
}
} // namespace detail

View File

@@ -31,11 +31,10 @@ namespace detail
std::vector<std::string>
get_unparsed_ros_arguments(
int argc, char const * const * argv,
[[maybe_unused]] int argc, char const * const * argv,
rcl_arguments_t * arguments,
rcl_allocator_t allocator)
{
(void)argc;
std::vector<std::string> unparsed_ros_arguments;
int unparsed_ros_args_count = rcl_arguments_get_count_unparsed_ros(arguments);
if (unparsed_ros_args_count > 0) {

View File

@@ -93,7 +93,9 @@ throw_from_rcl_error(
RCLErrorBase::RCLErrorBase(rcl_ret_t ret, const rcl_error_state_t * error_state)
: ret(ret), message(error_state->message), file(error_state->file), line(error_state->line_number),
formatted_message(rcl_get_error_string().str)
{}
{
rcl_reset_error();
}
RCLError::RCLError(
rcl_ret_t ret,

View File

@@ -18,6 +18,7 @@
#include <iterator>
#include <memory>
#include <map>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
@@ -52,6 +53,7 @@ class rclcpp::ExecutorImplementation {};
Executor::Executor(const std::shared_ptr<rclcpp::Context> & context)
: spinning(false),
context_(context),
entities_need_rebuild_(true),
collector_(nullptr),
wait_set_({}, {}, {}, {}, {}, {}, context)
@@ -66,7 +68,7 @@ Executor::Executor(const rclcpp::ExecutorOptions & options)
notify_waitable_(std::make_shared<rclcpp::executors::ExecutorNotifyWaitable>(
[this]() {
this->entities_need_rebuild_.store(true);
})),
}, options.context)),
entities_need_rebuild_(true),
collector_(notify_waitable_),
wait_set_({}, {}, {}, {}, {}, {}, options.context),
@@ -84,7 +86,9 @@ Executor::Executor(const rclcpp::ExecutorOptions & options)
notify_waitable_->add_guard_condition(interrupt_guard_condition_);
notify_waitable_->add_guard_condition(shutdown_guard_condition_);
wait_set_.add_waitable(notify_waitable_);
// we need to initially rebuild the collection,
// so that the notify_waitable_ is added
collect_entities();
}
Executor::~Executor()
@@ -129,7 +133,7 @@ Executor::~Executor()
}
void
Executor::trigger_entity_recollect(bool notify)
Executor::handle_updated_entities(bool notify)
{
this->entities_need_rebuild_.store(true);
@@ -167,32 +171,36 @@ Executor::get_automatically_added_callback_groups_from_nodes()
void
Executor::add_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
[[maybe_unused]] rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
bool notify)
{
(void) node_ptr;
this->collector_.add_callback_group(group_ptr);
try {
this->trigger_entity_recollect(notify);
this->handle_updated_entities(notify);
} catch (const rclcpp::exceptions::RCLError & ex) {
throw std::runtime_error(
std::string(
"Failed to trigger guard condition on callback group add: ") + ex.what());
"Failed to handle entities update on callback group add: ") + ex.what());
}
}
void
Executor::add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify)
{
if (node_ptr->get_context() != context_) {
throw std::runtime_error(
"add_node() called with a node with a different context from this executor");
}
this->collector_.add_node(node_ptr);
try {
this->trigger_entity_recollect(notify);
this->handle_updated_entities(notify);
} catch (const rclcpp::exceptions::RCLError & ex) {
throw std::runtime_error(
std::string(
"Failed to trigger guard condition on node add: ") + ex.what());
"Failed to handle entities update on node add: ") + ex.what());
}
}
@@ -204,11 +212,11 @@ Executor::remove_callback_group(
this->collector_.remove_callback_group(group_ptr);
try {
this->trigger_entity_recollect(notify);
this->handle_updated_entities(notify);
} catch (const rclcpp::exceptions::RCLError & ex) {
throw std::runtime_error(
std::string(
"Failed to trigger guard condition on callback group remove: ") + ex.what());
"Failed to handle entities update on callback group remove: ") + ex.what());
}
}
@@ -224,11 +232,11 @@ Executor::remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node
this->collector_.remove_node(node_ptr);
try {
this->trigger_entity_recollect(notify);
this->handle_updated_entities(notify);
} catch (const rclcpp::exceptions::RCLError & ex) {
throw std::runtime_error(
std::string(
"Failed to trigger guard condition on node remove: ") + ex.what());
"Failed to handle entities update on node remove: ") + ex.what());
}
}
@@ -371,7 +379,14 @@ Executor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
// both spin_some and spin_all wait for work at the beginning
wait_result_.reset();
wait_for_work(std::chrono::milliseconds(0));
bool just_waited = true;
bool entity_states_fully_polled = true;
if (entities_need_rebuild_) {
// if the last wait triggered a collection rebuild, we need to call
// wait_for_work once more, in order to do a collection rebuild and collect
// events from the just added entities
entity_states_fully_polled = false;
}
// The logic of this while loop is as follows:
//
@@ -393,12 +408,14 @@ Executor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
AnyExecutable any_exec;
if (get_next_ready_executable(any_exec)) {
execute_any_executable(any_exec);
just_waited = false;
// during the execution some entity might got ready therefore we need
// to repoll the states of all entities
entity_states_fully_polled = false;
} else {
// if nothing is ready, reset the result to clear it
wait_result_.reset();
if (just_waited) {
if (entity_states_fully_polled) {
// there was no work after just waiting, always exit in this case
// before the exhaustive condition can be checked
break;
@@ -408,7 +425,13 @@ Executor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
// if exhaustive, wait for work again
// this only happens for spin_all; spin_some only waits at the start
wait_for_work(std::chrono::milliseconds(0));
just_waited = true;
entity_states_fully_polled = true;
if (entities_need_rebuild_) {
// if the last wait triggered a collection rebuild, we need to call
// wait_for_work once more, in order to do a collection rebuild and
// collect events from the just added entities
entity_states_fully_polled = false;
}
} else {
break;
}
@@ -568,6 +591,7 @@ Executor::execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
"rcl_return_loaned_message_from_subscription() failed for subscription on topic "
"'%s': %s",
subscription->get_topic_name(), rcl_get_error_string().str);
rcl_reset_error();
}
loaned_msg = nullptr;
}
@@ -731,11 +755,14 @@ Executor::wait_for_work(std::chrono::nanoseconds timeout)
{
std::lock_guard<std::mutex> guard(mutex_);
if (this->entities_need_rebuild_.exchange(false) || current_collection_.empty()) {
this->collect_entities();
}
}
this->wait_result_.emplace(wait_set_.wait(timeout));
if (!this->wait_result_ || this->wait_result_->kind() == WaitResultKind::Empty) {
RCUTILS_LOG_WARN_NAMED(
"rclcpp",

View File

@@ -13,6 +13,7 @@
// limitations under the License.
#include "rclcpp/executors.hpp"
#include "rcpputils/compile_warnings.hpp"
void
rclcpp::spin_all(
@@ -25,12 +26,6 @@ rclcpp::spin_all(
exec.spin_node_all(node_ptr, max_duration);
}
void
rclcpp::spin_all(rclcpp::Node::SharedPtr node_ptr, std::chrono::nanoseconds max_duration)
{
rclcpp::spin_all(node_ptr->get_node_base_interface(), max_duration);
}
void
rclcpp::spin_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr)
{
@@ -40,12 +35,6 @@ rclcpp::spin_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr
exec.spin_node_some(node_ptr);
}
void
rclcpp::spin_some(rclcpp::Node::SharedPtr node_ptr)
{
rclcpp::spin_some(node_ptr->get_node_base_interface());
}
void
rclcpp::spin(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr)
{
@@ -62,3 +51,19 @@ rclcpp::spin(rclcpp::Node::SharedPtr node_ptr)
{
rclcpp::spin(node_ptr->get_node_base_interface());
}
void
rclcpp::spin_all(rclcpp::Node::SharedPtr node_ptr, std::chrono::nanoseconds max_duration)
{
RCPPUTILS_DEPRECATION_WARNING_OFF_START
rclcpp::spin_all(node_ptr->get_node_base_interface(), max_duration);
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
}
void
rclcpp::spin_some(rclcpp::Node::SharedPtr node_ptr)
{
RCPPUTILS_DEPRECATION_WARNING_OFF_START
rclcpp::spin_some(node_ptr->get_node_base_interface());
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
}

View File

@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <iostream>
#include "rclcpp/exceptions.hpp"
#include "rclcpp/executors/executor_notify_waitable.hpp"
@@ -22,8 +20,11 @@ namespace rclcpp
namespace executors
{
ExecutorNotifyWaitable::ExecutorNotifyWaitable(std::function<void(void)> on_execute_callback)
: execute_callback_(on_execute_callback)
ExecutorNotifyWaitable::ExecutorNotifyWaitable(
std::function<void(void)> on_execute_callback,
const rclcpp::Context::SharedPtr & context)
: execute_callback_(on_execute_callback),
guard_condition_(std::make_shared<rclcpp::GuardCondition>(context))
{
}
@@ -32,6 +33,9 @@ ExecutorNotifyWaitable::ExecutorNotifyWaitable(ExecutorNotifyWaitable & other)
std::lock_guard<std::mutex> lock(other.guard_condition_mutex_);
this->execute_callback_ = other.execute_callback_;
this->notify_guard_conditions_ = other.notify_guard_conditions_;
this->guard_condition_ = other.guard_condition_;
this->idxs_of_added_guard_condition_ = other.idxs_of_added_guard_condition_;
this->needs_processing = other.needs_processing;
}
ExecutorNotifyWaitable & ExecutorNotifyWaitable::operator=(ExecutorNotifyWaitable & other)
@@ -40,6 +44,9 @@ ExecutorNotifyWaitable & ExecutorNotifyWaitable::operator=(ExecutorNotifyWaitabl
std::lock_guard<std::mutex> lock(other.guard_condition_mutex_);
this->execute_callback_ = other.execute_callback_;
this->notify_guard_conditions_ = other.notify_guard_conditions_;
this->guard_condition_ = other.guard_condition_;
this->idxs_of_added_guard_condition_ = other.idxs_of_added_guard_condition_;
this->needs_processing = other.needs_processing;
}
return *this;
}
@@ -49,21 +56,42 @@ ExecutorNotifyWaitable::add_to_wait_set(rcl_wait_set_t & wait_set)
{
std::lock_guard<std::mutex> lock(guard_condition_mutex_);
// Note: no guard conditions need to be re-triggered, since the guard
// conditions in this class are not tracking a stateful condition, but instead
// only serve to interrupt the wait set when new information is available to
// consider.
for (auto weak_guard_condition : this->notify_guard_conditions_) {
auto guard_condition = weak_guard_condition.lock();
if (!guard_condition) {continue;}
idxs_of_added_guard_condition_.clear();
idxs_of_added_guard_condition_.reserve(notify_guard_conditions_.size());
rcl_guard_condition_t * cond = &guard_condition->get_rcl_guard_condition();
rcl_ret_t ret = rcl_wait_set_add_guard_condition(&wait_set, cond, NULL);
if(needs_processing) {
rcl_guard_condition_t * cond = &guard_condition_->get_rcl_guard_condition();
size_t rcl_index;
rcl_ret_t ret = rcl_wait_set_add_guard_condition(&wait_set, cond, &rcl_index);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(
ret, "failed to add guard condition to wait set");
}
idxs_of_added_guard_condition_.push_back(rcl_index);
// we want to directly wake up any way, not need to add the other guard conditions
guard_condition_->trigger();
return;
}
// Note: no guard conditions need to be re-triggered, since the guard
// conditions in this class are not tracking a stateful condition, but instead
// only serve to interrupt the wait set when new information is available to
// consider.
for (const auto & guard_condition : this->notify_guard_conditions_) {
rcl_guard_condition_t * cond = &guard_condition->get_rcl_guard_condition();
size_t rcl_index;
rcl_ret_t ret = rcl_wait_set_add_guard_condition(&wait_set, cond, &rcl_index);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(
ret, "failed to add guard condition to wait set");
}
idxs_of_added_guard_condition_.push_back(rcl_index);
}
}
@@ -73,27 +101,33 @@ ExecutorNotifyWaitable::is_ready(const rcl_wait_set_t & wait_set)
std::lock_guard<std::mutex> lock(guard_condition_mutex_);
bool any_ready = false;
for (size_t ii = 0; ii < wait_set.size_of_guard_conditions; ++ii) {
const auto * rcl_guard_condition = wait_set.guard_conditions[ii];
for (size_t rcl_index : idxs_of_added_guard_condition_) {
if(rcl_index >= wait_set.size_of_guard_conditions) {
throw std::runtime_error(
"ExecutorNotifyWaitable::is_ready: Internal error, got index out of range");
}
const auto * rcl_guard_condition = wait_set.guard_conditions[rcl_index];
if (nullptr == rcl_guard_condition) {
continue;
}
for (const auto & weak_guard_condition : this->notify_guard_conditions_) {
auto guard_condition = weak_guard_condition.lock();
if (guard_condition && &guard_condition->get_rcl_guard_condition() == rcl_guard_condition) {
any_ready = true;
break;
}
}
any_ready = true;
needs_processing = true;
break;
}
return any_ready;
}
void
ExecutorNotifyWaitable::execute(const std::shared_ptr<void> & data)
ExecutorNotifyWaitable::execute(const std::shared_ptr<void> & /*data*/)
{
(void) data;
std::lock_guard<std::mutex> lock(execute_mutex_);
needs_processing = false;
this->execute_callback_();
}
@@ -104,9 +138,8 @@ ExecutorNotifyWaitable::take_data()
}
std::shared_ptr<void>
ExecutorNotifyWaitable::take_data_by_entity_id(size_t id)
ExecutorNotifyWaitable::take_data_by_entity_id([[maybe_unused]] size_t id)
{
(void) id;
return nullptr;
}
@@ -124,11 +157,7 @@ ExecutorNotifyWaitable::set_on_ready_callback(std::function<void(size_t, int)> c
std::lock_guard<std::mutex> lock(guard_condition_mutex_);
on_ready_callback_ = gc_callback;
for (auto weak_gc : notify_guard_conditions_) {
auto gc = weak_gc.lock();
if (!gc) {
continue;
}
for (const auto & gc : notify_guard_conditions_) {
gc->set_on_trigger_callback(on_ready_callback_);
}
}
@@ -140,22 +169,26 @@ ExecutorNotifyWaitable::clear_on_ready_callback()
std::lock_guard<std::mutex> lock(guard_condition_mutex_);
on_ready_callback_ = nullptr;
for (auto weak_gc : notify_guard_conditions_) {
auto gc = weak_gc.lock();
if (!gc) {
continue;
}
for (const auto & gc : notify_guard_conditions_) {
gc->set_on_trigger_callback(nullptr);
}
}
RCLCPP_PUBLIC
void
ExecutorNotifyWaitable::set_execute_callback(std::function<void(void)> on_execute_callback)
{
std::lock_guard<std::mutex> lock(execute_mutex_);
execute_callback_ = on_execute_callback;
}
void
ExecutorNotifyWaitable::add_guard_condition(rclcpp::GuardCondition::WeakPtr weak_guard_condition)
{
std::lock_guard<std::mutex> lock(guard_condition_mutex_);
auto guard_condition = weak_guard_condition.lock();
if (guard_condition && notify_guard_conditions_.count(weak_guard_condition) == 0) {
notify_guard_conditions_.insert(weak_guard_condition);
const auto & guard_condition = weak_guard_condition.lock();
if (guard_condition && notify_guard_conditions_.count(guard_condition) == 0) {
notify_guard_conditions_.insert(guard_condition);
if (on_ready_callback_) {
guard_condition->set_on_trigger_callback(on_ready_callback_);
}
@@ -166,11 +199,17 @@ void
ExecutorNotifyWaitable::remove_guard_condition(rclcpp::GuardCondition::WeakPtr weak_guard_condition)
{
std::lock_guard<std::mutex> lock(guard_condition_mutex_);
if (notify_guard_conditions_.count(weak_guard_condition) != 0) {
notify_guard_conditions_.erase(weak_guard_condition);
auto guard_condition = weak_guard_condition.lock();
const auto & guard_condition = weak_guard_condition.lock();
if (!guard_condition) {
// If the lock did not work, the guard condition can't be
// saved in the sets, therefore we don't need to remove it
return;
}
auto it = notify_guard_conditions_.find(guard_condition);
if (it != notify_guard_conditions_.end()) {
notify_guard_conditions_.erase(it);
// If this notify waitable doesn't have an on_ready_callback, then there's nothing to unset
if (guard_condition && on_ready_callback_) {
if (on_ready_callback_) {
guard_condition->set_on_trigger_callback(nullptr);
}
}
@@ -183,5 +222,12 @@ ExecutorNotifyWaitable::get_number_of_ready_guard_conditions()
return notify_guard_conditions_.size();
}
std::vector<std::shared_ptr<rclcpp::TimerBase>>
ExecutorNotifyWaitable::get_timers() const
{
return {};
}
} // namespace executors
} // namespace rclcpp

View File

@@ -79,9 +79,8 @@ MultiThreadedExecutor::get_number_of_threads()
}
void
MultiThreadedExecutor::run(size_t this_thread_number)
MultiThreadedExecutor::run([[maybe_unused]] size_t this_thread_number)
{
(void)this_thread_number;
while (rclcpp::ok(this->context_) && spinning.load()) {
rclcpp::AnyExecutable any_exec;
{

View File

@@ -1,204 +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.
#include "rclcpp/executors/executor_entities_collection.hpp"
#include "rcpputils/scope_exit.hpp"
#include "rclcpp/executors/static_single_threaded_executor.hpp"
#include "rclcpp/any_executable.hpp"
using rclcpp::executors::StaticSingleThreadedExecutor;
StaticSingleThreadedExecutor::StaticSingleThreadedExecutor(const rclcpp::ExecutorOptions & options)
: rclcpp::Executor(options)
{
}
StaticSingleThreadedExecutor::~StaticSingleThreadedExecutor() {}
void
StaticSingleThreadedExecutor::spin()
{
if (spinning.exchange(true)) {
throw std::runtime_error("spin() called while already spinning");
}
RCPPUTILS_SCOPE_EXIT(this->spinning.store(false); );
// This is essentially the contents of the rclcpp::Executor::wait_for_work method,
// except we need to keep the wait result to reproduce the StaticSingleThreadedExecutor
// behavior.
while (rclcpp::ok(this->context_) && spinning.load()) {
this->spin_once_impl(std::chrono::nanoseconds(-1));
}
}
void
StaticSingleThreadedExecutor::spin_some(std::chrono::nanoseconds max_duration)
{
// In this context a 0 input max_duration means no duration limit
if (std::chrono::nanoseconds(0) == max_duration) {
max_duration = std::chrono::nanoseconds::max();
}
return this->spin_some_impl(max_duration, false);
}
void
StaticSingleThreadedExecutor::spin_all(std::chrono::nanoseconds max_duration)
{
if (max_duration < std::chrono::nanoseconds(0)) {
throw std::invalid_argument("max_duration must be greater than or equal to 0");
}
return this->spin_some_impl(max_duration, true);
}
void
StaticSingleThreadedExecutor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
{
auto start = std::chrono::steady_clock::now();
auto max_duration_not_elapsed = [max_duration, start]() {
const auto spin_forever = std::chrono::nanoseconds(0) == max_duration;
const auto cur_duration = std::chrono::steady_clock::now() - start;
return spin_forever || (cur_duration < max_duration);
};
if (spinning.exchange(true)) {
throw std::runtime_error("spin_some() called while already spinning");
}
RCPPUTILS_SCOPE_EXIT(this->spinning.store(false););
while (rclcpp::ok(context_) && spinning.load() && max_duration_not_elapsed()) {
// Get executables that are ready now
std::lock_guard<std::mutex> guard(mutex_);
auto wait_result = this->collect_and_wait(std::chrono::nanoseconds(0));
if (wait_result.has_value()) {
// Execute ready executables
bool work_available = this->execute_ready_executables(
current_collection_,
wait_result.value(),
false);
if (!work_available || !exhaustive) {
break;
}
}
}
}
void
StaticSingleThreadedExecutor::spin_once_impl(std::chrono::nanoseconds timeout)
{
if (rclcpp::ok(context_) && spinning.load()) {
std::lock_guard<std::mutex> guard(mutex_);
auto wait_result = this->collect_and_wait(timeout);
if (wait_result.has_value()) {
this->execute_ready_executables(current_collection_, wait_result.value(), true);
}
}
}
std::optional<rclcpp::WaitResult<rclcpp::WaitSet>>
StaticSingleThreadedExecutor::collect_and_wait(std::chrono::nanoseconds timeout)
{
if (this->entities_need_rebuild_.exchange(false) || current_collection_.empty()) {
this->collect_entities();
}
auto wait_result = wait_set_.wait(std::chrono::nanoseconds(timeout));
if (wait_result.kind() == WaitResultKind::Empty) {
RCUTILS_LOG_WARN_NAMED(
"rclcpp",
"empty wait set received in wait(). This should never happen.");
return {};
} else {
if (wait_result.kind() == WaitResultKind::Ready && current_notify_waitable_) {
auto & rcl_wait_set = wait_result.get_wait_set().get_rcl_wait_set();
if (current_notify_waitable_->is_ready(rcl_wait_set)) {
current_notify_waitable_->execute(current_notify_waitable_->take_data());
}
}
}
return wait_result;
}
// This preserves the "scheduling semantics" of the StaticSingleThreadedExecutor
// from the original implementation.
bool StaticSingleThreadedExecutor::execute_ready_executables(
const rclcpp::executors::ExecutorEntitiesCollection & collection,
rclcpp::WaitResult<rclcpp::WaitSet> & wait_result,
bool spin_once)
{
bool any_ready_executable = false;
if (wait_result.kind() != rclcpp::WaitResultKind::Ready) {
return any_ready_executable;
}
while (auto subscription = wait_result.next_ready_subscription()) {
auto entity_iter = collection.subscriptions.find(subscription->get_subscription_handle().get());
if (entity_iter != collection.subscriptions.end()) {
execute_subscription(subscription);
any_ready_executable = true;
if (spin_once) {return any_ready_executable;}
}
}
size_t current_timer_index = 0;
while (true) {
auto [timer, timer_index] = wait_result.peek_next_ready_timer(current_timer_index);
if (nullptr == timer) {
break;
}
current_timer_index = timer_index;
auto entity_iter = collection.timers.find(timer->get_timer_handle().get());
if (entity_iter != collection.timers.end()) {
wait_result.clear_timer_with_index(current_timer_index);
auto data = timer->call();
if (!data) {
// someone canceled the timer between is_ready and call
continue;
}
execute_timer(std::move(timer), data);
any_ready_executable = true;
if (spin_once) {return any_ready_executable;}
}
}
while (auto client = wait_result.next_ready_client()) {
auto entity_iter = collection.clients.find(client->get_client_handle().get());
if (entity_iter != collection.clients.end()) {
execute_client(client);
any_ready_executable = true;
if (spin_once) {return any_ready_executable;}
}
}
while (auto service = wait_result.next_ready_service()) {
auto entity_iter = collection.services.find(service->get_service_handle().get());
if (entity_iter != collection.services.end()) {
execute_service(service);
any_ready_executable = true;
if (spin_once) {return any_ready_executable;}
}
}
while (auto waitable = wait_result.next_ready_waitable()) {
auto entity_iter = collection.waitables.find(waitable.get());
if (entity_iter != collection.waitables.end()) {
const auto data = waitable->take_data();
waitable->execute(data);
any_ready_executable = true;
if (spin_once) {return any_ready_executable;}
}
}
return any_ready_executable;
}

View File

@@ -25,9 +25,9 @@ using namespace std::chrono_literals;
using rclcpp::experimental::executors::EventsExecutor;
EventsExecutor::EventsExecutor(
const rclcpp::ExecutorOptions & options,
rclcpp::experimental::executors::EventsQueue::UniquePtr events_queue,
bool execute_timers_separate_thread,
const rclcpp::ExecutorOptions & options)
bool execute_timers_separate_thread)
: rclcpp::Executor(options)
{
// Get ownership of the queue used to store events.
@@ -52,29 +52,36 @@ EventsExecutor::EventsExecutor(
timers_manager_ =
std::make_shared<rclcpp::experimental::TimersManager>(context_, timer_on_ready_cb);
this->current_entities_collection_ =
std::make_shared<rclcpp::executors::ExecutorEntitiesCollection>();
entities_need_rebuild_ = false;
notify_waitable_ = std::make_shared<rclcpp::executors::ExecutorNotifyWaitable>(
this->setup_notify_waitable();
// Ensure that the entities collection is empty (the base class may have added elements
// that we are not interested in)
this->current_collection_.clear();
// Make sure that the notify waitable is immediately added to the collection
// to avoid missing events
this->add_notify_waitable_to_collection(current_collection_.waitables);
}
void
EventsExecutor::setup_notify_waitable()
{
// The base class already created this object but the events-executor
// needs different callbacks.
assert(notify_waitable_ && "The notify waitable should have already been constructed");
notify_waitable_->set_execute_callback(
[this]() {
// This callback is invoked when:
// - the interrupt or shutdown guard condition is triggered:
// ---> we need to wake up the executor so that it can terminate
// - a node or callback group guard condition is triggered:
// ---> the entities collection is changed, we need to update callbacks
this->refresh_current_collection_from_callback_groups();
this->handle_updated_entities(false);
});
// Make sure that the notify waitable is immediately added to the collection
// to avoid missing events
this->add_notify_waitable_to_collection(current_entities_collection_->waitables);
notify_waitable_->add_guard_condition(interrupt_guard_condition_);
notify_waitable_->add_guard_condition(shutdown_guard_condition_);
notify_waitable_->set_on_ready_callback(
this->create_waitable_callback(notify_waitable_.get()));
auto notify_waitable_entity_id = notify_waitable_.get();
notify_waitable_->set_on_ready_callback(
[this, notify_waitable_entity_id](size_t num_events, int waitable_data) {
@@ -84,7 +91,7 @@ EventsExecutor::EventsExecutor(
// For the same reason, if an event of this type has already been pushed but it has not been
// processed yet, we avoid pushing additional events.
(void)num_events;
if (notify_waitable_event_pushed_.exchange(true)) {
if (entities_need_rebuild_.exchange(true)) {
return;
}
@@ -92,9 +99,6 @@ EventsExecutor::EventsExecutor(
{notify_waitable_entity_id, nullptr, waitable_data, ExecutorEventType::WAITABLE_EVENT, 1};
this->events_queue_->enqueue(event);
});
this->entities_collector_ =
std::make_shared<rclcpp::executors::ExecutorEntitiesCollector>(notify_waitable_);
}
EventsExecutor::~EventsExecutor()
@@ -168,7 +172,7 @@ EventsExecutor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhau
// A non-exhaustive spin would not check for work a second time, thus delaying the execution
// of some entities to the next invocation of spin.
if (!exhaustive) {
this->refresh_current_collection_from_callback_groups();
this->handle_updated_entities(false);
}
// Get the number of events and timers ready at start
@@ -236,46 +240,6 @@ EventsExecutor::spin_once_impl(std::chrono::nanoseconds timeout)
}
}
void
EventsExecutor::add_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify)
{
// This field is unused because we don't have to wake up the executor when a node is added.
(void) notify;
// Add node to entities collector
this->entities_collector_->add_node(node_ptr);
this->refresh_current_collection_from_callback_groups();
}
void
EventsExecutor::add_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify)
{
this->add_node(node_ptr->get_node_base_interface(), notify);
}
void
EventsExecutor::remove_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify)
{
// This field is unused because we don't have to wake up the executor when a node is removed.
(void)notify;
// Remove node from entities collector.
// This will result in un-setting all the event callbacks from its entities.
// After this function returns, this executor will not receive any more events associated
// to these entities.
this->entities_collector_->remove_node(node_ptr);
this->refresh_current_collection_from_callback_groups();
}
void
EventsExecutor::remove_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify)
{
this->remove_node(node_ptr->get_node_base_interface(), notify);
}
void
EventsExecutor::execute_event(const ExecutorEvent & event)
@@ -285,10 +249,9 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
{
rclcpp::ClientBase::SharedPtr client;
{
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
client = this->retrieve_entity(
static_cast<const rcl_client_t *>(event.entity_key),
current_entities_collection_->clients);
current_collection_.clients);
}
if (client) {
for (size_t i = 0; i < event.num_events; i++) {
@@ -302,10 +265,9 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
{
rclcpp::SubscriptionBase::SharedPtr subscription;
{
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
subscription = this->retrieve_entity(
static_cast<const rcl_subscription_t *>(event.entity_key),
current_entities_collection_->subscriptions);
current_collection_.subscriptions);
}
if (subscription) {
for (size_t i = 0; i < event.num_events; i++) {
@@ -318,10 +280,9 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
{
rclcpp::ServiceBase::SharedPtr service;
{
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
service = this->retrieve_entity(
static_cast<const rcl_service_t *>(event.entity_key),
current_entities_collection_->services);
current_collection_.services);
}
if (service) {
for (size_t i = 0; i < event.num_events; i++) {
@@ -341,10 +302,9 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
{
rclcpp::Waitable::SharedPtr waitable;
{
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
waitable = this->retrieve_entity(
static_cast<const rclcpp::Waitable *>(event.entity_key),
current_entities_collection_->waitables);
current_collection_.waitables);
}
if (waitable) {
for (size_t i = 0; i < event.num_events; i++) {
@@ -358,71 +318,21 @@ EventsExecutor::execute_event(const ExecutorEvent & event)
}
void
EventsExecutor::add_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
bool notify)
{
// This field is unused because we don't have to wake up
// the executor when a callback group is added.
(void)notify;
(void)node_ptr;
this->entities_collector_->add_callback_group(group_ptr);
this->refresh_current_collection_from_callback_groups();
}
void
EventsExecutor::remove_callback_group(
rclcpp::CallbackGroup::SharedPtr group_ptr, bool notify)
{
// This field is unused because we don't have to wake up
// the executor when a callback group is removed.
(void)notify;
this->entities_collector_->remove_callback_group(group_ptr);
this->refresh_current_collection_from_callback_groups();
}
std::vector<rclcpp::CallbackGroup::WeakPtr>
EventsExecutor::get_all_callback_groups()
{
this->entities_collector_->update_collections();
return this->entities_collector_->get_all_callback_groups();
}
std::vector<rclcpp::CallbackGroup::WeakPtr>
EventsExecutor::get_manually_added_callback_groups()
{
this->entities_collector_->update_collections();
return this->entities_collector_->get_manually_added_callback_groups();
}
std::vector<rclcpp::CallbackGroup::WeakPtr>
EventsExecutor::get_automatically_added_callback_groups_from_nodes()
{
this->entities_collector_->update_collections();
return this->entities_collector_->get_automatically_added_callback_groups();
}
void
EventsExecutor::refresh_current_collection_from_callback_groups()
EventsExecutor::handle_updated_entities([[maybe_unused]] bool notify)
{
// Do not rebuild if we don't need to.
// A rebuild event could be generated, but then
// this function could end up being called from somewhere else
// before that event gets processed, for example if
// a node or callback group is manually added to the executor.
const bool notify_waitable_triggered = notify_waitable_event_pushed_.exchange(false);
if (!notify_waitable_triggered && !this->entities_collector_->has_pending()) {
const bool notify_waitable_triggered = entities_need_rebuild_.exchange(false);
if (!notify_waitable_triggered && !this->collector_.has_pending()) {
return;
}
// Build the new collection
this->entities_collector_->update_collections();
auto callback_groups = this->entities_collector_->get_all_callback_groups();
this->collector_.update_collections();
auto callback_groups = this->collector_.get_all_callback_groups();
rclcpp::executors::ExecutorEntitiesCollection new_collection;
rclcpp::executors::build_entities_collection(callback_groups, new_collection);
@@ -432,14 +342,11 @@ EventsExecutor::refresh_current_collection_from_callback_groups()
// We could explicitly check for the notify waitable ID when we receive a waitable event
// but I think that it's better if the waitable was in the collection and it could be
// retrieved in the "standard" way.
// To do it, we need to add the notify waitable as an entry in both the new and
// current collections such that it's neither added or removed.
// To do it, we need to add the notify waitable as an entry in the new collection
// such that it's neither added or removed (it should have already been added
// to the current collection in the constructor)
this->add_notify_waitable_to_collection(new_collection.waitables);
// Acquire lock before modifying the current collection
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
this->add_notify_waitable_to_collection(current_entities_collection_->waitables);
this->refresh_current_collection(new_collection);
}
@@ -448,14 +355,19 @@ EventsExecutor::refresh_current_collection(
const rclcpp::executors::ExecutorEntitiesCollection & new_collection)
{
// Acquire lock before modifying the current collection
std::lock_guard<std::recursive_mutex> lock(collection_mutex_);
std::lock_guard<std::mutex> guard(mutex_);
current_entities_collection_->timers.update(
// Remove expired entities to ensure re-initialized objects
// are updated. This fixes issues with stale state entities.
// See: https://github.com/ros2/rclcpp/pull/2586
current_collection_.remove_expired_entities();
current_collection_.timers.update(
new_collection.timers,
[this](rclcpp::TimerBase::SharedPtr timer) {timers_manager_->add_timer(timer);},
[this](rclcpp::TimerBase::SharedPtr timer) {timers_manager_->remove_timer(timer);});
current_entities_collection_->subscriptions.update(
current_collection_.subscriptions.update(
new_collection.subscriptions,
[this](auto subscription) {
subscription->set_on_new_message_callback(
@@ -464,7 +376,7 @@ EventsExecutor::refresh_current_collection(
},
[](auto subscription) {subscription->clear_on_new_message_callback();});
current_entities_collection_->clients.update(
current_collection_.clients.update(
new_collection.clients,
[this](auto client) {
client->set_on_new_response_callback(
@@ -473,7 +385,7 @@ EventsExecutor::refresh_current_collection(
},
[](auto client) {client->clear_on_new_response_callback();});
current_entities_collection_->services.update(
current_collection_.services.update(
new_collection.services,
[this](auto service) {
service->set_on_new_request_callback(
@@ -484,18 +396,26 @@ EventsExecutor::refresh_current_collection(
// DO WE NEED THIS? WE ARE NOT DOING ANYTHING WITH GUARD CONDITIONS
/*
current_entities_collection_->guard_conditions.update(new_collection.guard_conditions,
current_collection_.guard_conditions.update(new_collection.guard_conditions,
[](auto guard_condition) {(void)guard_condition;},
[](auto guard_condition) {guard_condition->set_on_trigger_callback(nullptr);});
*/
current_entities_collection_->waitables.update(
current_collection_.waitables.update(
new_collection.waitables,
[this](auto waitable) {
waitable->set_on_ready_callback(
this->create_waitable_callback(waitable.get()));
for (const auto & t : waitable->get_timers()) {
timers_manager_->add_timer(t);
}
},
[](auto waitable) {waitable->clear_on_ready_callback();});
[this](auto waitable) {
waitable->clear_on_ready_callback();
for (const auto & t : waitable->get_timers()) {
timers_manager_->remove_timer(t);
}
});
}
std::function<void(size_t)>

View File

@@ -31,22 +31,31 @@ GenericClient::GenericClient(
rcl_client_options_t & client_options)
: ClientBase(node_base, node_graph)
{
ts_lib_ = get_typesupport_library(
service_type, "rosidl_typesupport_cpp");
const rosidl_service_type_support_t * service_ts;
try {
ts_lib_ = get_typesupport_library(
service_type, "rosidl_typesupport_cpp");
auto service_ts_ = get_service_typesupport_handle(
service_type, "rosidl_typesupport_cpp", *ts_lib_);
service_ts = get_service_typesupport_handle(
service_type, "rosidl_typesupport_cpp", *ts_lib_);
auto response_type_support_intro = get_message_typesupport_handle(
service_ts_->response_typesupport,
rosidl_typesupport_introspection_cpp::typesupport_identifier);
response_members_ = static_cast<const rosidl_typesupport_introspection_cpp::MessageMembers *>(
response_type_support_intro->data);
auto response_type_support_intro = get_message_typesupport_handle(
service_ts->response_typesupport,
rosidl_typesupport_introspection_cpp::typesupport_identifier);
response_members_ = static_cast<const rosidl_typesupport_introspection_cpp::MessageMembers *>(
response_type_support_intro->data);
} catch (std::runtime_error & err) {
RCLCPP_ERROR(
rclcpp::get_node_logger(node_handle_.get()).get_child("rclcpp"),
"Invalid service type: %s",
err.what());
throw rclcpp::exceptions::InvalidServiceTypeError(err.what());
}
rcl_ret_t ret = rcl_client_init(
this->get_client_handle().get(),
this->get_rcl_node_handle(),
service_ts_,
service_ts,
service_name.c_str(),
&client_options);
if (ret != RCL_RET_OK) {
@@ -100,6 +109,13 @@ GenericClient::handle_response(
if (std::holds_alternative<Promise>(value)) {
auto & promise = std::get<Promise>(value);
promise.set_value(std::move(response));
} else if (std::holds_alternative<CallbackTypeValueVariant>(value)) {
auto & inner = std::get<CallbackTypeValueVariant>(value);
const auto & callback = std::get<CallbackType>(inner);
auto & promise = std::get<Promise>(inner);
auto & future = std::get<SharedFuture>(inner);
promise.set_value(std::move(response));
callback(std::move(future));
}
}
@@ -119,6 +135,18 @@ GenericClient::remove_pending_request(int64_t request_id)
return pending_requests_.erase(request_id) != 0u;
}
bool
GenericClient::remove_pending_request(const FutureAndRequestId & future)
{
return this->remove_pending_request(future.request_id);
}
bool
GenericClient::remove_pending_request(const SharedFutureAndRequestId & future)
{
return this->remove_pending_request(future.request_id);
}
std::optional<GenericClient::CallbackInfoVariant>
GenericClient::get_and_erase_pending_request(int64_t request_number)
{

View File

@@ -0,0 +1,172 @@
// 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.
#include "rclcpp/generic_service.hpp"
namespace rclcpp
{
GenericService::GenericService(
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)
: ServiceBase(node_handle),
any_callback_(any_callback)
{
const rosidl_service_type_support_t * service_ts;
try {
ts_lib_ = get_typesupport_library(
service_type, "rosidl_typesupport_cpp");
service_ts = get_service_typesupport_handle(
service_type, "rosidl_typesupport_cpp", *ts_lib_);
auto request_type_support_intro = get_message_typesupport_handle(
service_ts->request_typesupport,
rosidl_typesupport_introspection_cpp::typesupport_identifier);
request_members_ = static_cast<const rosidl_typesupport_introspection_cpp::MessageMembers *>(
request_type_support_intro->data);
auto response_type_support_intro = get_message_typesupport_handle(
service_ts->response_typesupport,
rosidl_typesupport_introspection_cpp::typesupport_identifier);
response_members_ = static_cast<const rosidl_typesupport_introspection_cpp::MessageMembers *>(
response_type_support_intro->data);
} catch (std::runtime_error & err) {
RCLCPP_ERROR(
rclcpp::get_node_logger(node_handle_.get()).get_child("rclcpp"),
"Invalid service type: %s",
err.what());
throw rclcpp::exceptions::InvalidServiceTypeError(err.what());
}
// rcl does the static memory allocation here
service_handle_ = std::shared_ptr<rcl_service_t>(
new rcl_service_t, [handle = node_handle_, service_name](rcl_service_t * service)
{
if (rcl_service_fini(service, handle.get()) != RCL_RET_OK) {
RCLCPP_ERROR(
rclcpp::get_node_logger(handle.get()).get_child("rclcpp"),
"Error in destruction of rcl service handle: %s",
rcl_get_error_string().str);
rcl_reset_error();
}
delete service;
});
*service_handle_.get() = rcl_get_zero_initialized_service();
rcl_ret_t ret = rcl_service_init(
service_handle_.get(),
node_handle.get(),
service_ts,
service_name.c_str(),
&service_options);
if (ret != RCL_RET_OK) {
if (ret == RCL_RET_SERVICE_NAME_INVALID) {
auto rcl_node_handle = get_rcl_node_handle();
// this will throw on any validation problem
rcl_reset_error();
expand_topic_or_service_name(
service_name,
rcl_node_get_name(rcl_node_handle),
rcl_node_get_namespace(rcl_node_handle),
true);
}
rclcpp::exceptions::throw_from_rcl_error(ret, "could not create service");
}
TRACETOOLS_TRACEPOINT(
rclcpp_service_callback_added,
static_cast<const void *>(get_service_handle().get()),
static_cast<const void *>(&any_callback_));
#ifndef TRACETOOLS_DISABLED
any_callback_.register_callback_for_tracing();
#endif
}
bool
GenericService::take_request(
SharedRequest request_out,
rmw_request_id_t & request_id_out)
{
request_out = create_request();
return this->take_type_erased_request(request_out.get(), request_id_out);
}
std::shared_ptr<void>
GenericService::create_request()
{
Request request = new uint8_t[request_members_->size_of_];
request_members_->init_function(request, rosidl_runtime_cpp::MessageInitialization::ZERO);
return std::shared_ptr<void>(
request,
[this](void * p)
{
request_members_->fini_function(p);
delete[] reinterpret_cast<uint8_t *>(p);
});
}
std::shared_ptr<void>
GenericService::create_response()
{
Response response = new uint8_t[response_members_->size_of_];
response_members_->init_function(response, rosidl_runtime_cpp::MessageInitialization::ZERO);
return std::shared_ptr<void>(
response,
[this](void * p)
{
response_members_->fini_function(p);
delete[] reinterpret_cast<uint8_t *>(p);
});
}
std::shared_ptr<rmw_request_id_t>
GenericService::create_request_header()
{
return std::make_shared<rmw_request_id_t>();
}
void
GenericService::handle_request(
std::shared_ptr<rmw_request_id_t> request_header,
std::shared_ptr<void> request)
{
auto response = any_callback_.dispatch(
this->shared_from_this(), request_header, request, create_response());
if (response) {
send_response(*request_header, response);
}
}
void
GenericService::send_response(rmw_request_id_t & req_id, SharedResponse & response)
{
rcl_ret_t ret = rcl_send_response(get_service_handle().get(), &req_id, response.get());
if (ret == RCL_RET_TIMEOUT) {
RCLCPP_WARN(
node_logger_.get_child("rclcpp"),
"failed to send response to %s (timeout): %s",
this->get_service_name(), rcl_get_error_string().str);
rcl_reset_error();
return;
}
if (ret != RCL_RET_OK) {
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to send response");
}
}
} // namespace rclcpp

View File

@@ -56,10 +56,9 @@ GenericSubscription::handle_serialized_message(
void
GenericSubscription::handle_loaned_message(
void * message, const rclcpp::MessageInfo & message_info)
[[maybe_unused]] void * message,
[[maybe_unused]] const rclcpp::MessageInfo & message_info)
{
(void) message;
(void) message_info;
throw rclcpp::exceptions::UnimplementedError(
"handle_loaned_message is not implemented for GenericSubscription");
}
@@ -111,20 +110,17 @@ GenericSubscription::create_dynamic_message()
void
GenericSubscription::return_dynamic_message(
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message)
[[maybe_unused]] rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message)
{
(void) message;
throw rclcpp::exceptions::UnimplementedError(
"return_dynamic_message is not implemented for GenericSubscription");
}
void
GenericSubscription::handle_dynamic_message(
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
const rclcpp::MessageInfo & message_info)
[[maybe_unused]] const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
[[maybe_unused]] const rclcpp::MessageInfo & message_info)
{
(void) message;
(void) message_info;
throw rclcpp::exceptions::UnimplementedError(
"handle_dynamic_message is not implemented for GenericSubscription");
}

View File

@@ -19,7 +19,6 @@
#include <memory>
#include <string>
#include <vector>
#include "rcl/error_handling.h"
#include "rcl/types.h"
#include "rclcpp/detail/add_guard_condition_to_rcl_wait_set.hpp"
@@ -38,8 +37,7 @@ namespace graph_listener
{
GraphListener::GraphListener(const std::shared_ptr<Context> & parent_context)
: weak_parent_context_(parent_context),
rcl_parent_context_(parent_context->get_rcl_context()),
: rcl_parent_context_(parent_context->get_rcl_context()),
is_started_(false),
is_shutdown_(false),
interrupt_guard_condition_(parent_context)
@@ -72,23 +70,11 @@ void
GraphListener::start_if_not_started()
{
std::lock_guard<std::mutex> shutdown_lock(shutdown_mutex_);
if (is_shutdown_.load()) {
if (is_shutdown()) {
throw GraphListenerShutdownError();
}
auto parent_context = weak_parent_context_.lock();
if (!is_started_ && parent_context) {
// Register an on_shutdown hook to shtudown the graph listener.
// This is important to ensure that the wait set is finalized before
// destruction of static objects occurs.
std::weak_ptr<GraphListener> weak_this = shared_from_this();
parent_context->on_shutdown(
[weak_this]() {
auto shared_this = weak_this.lock();
if (shared_this) {
// should not throw from on_shutdown if it can be avoided
shared_this->shutdown(std::nothrow);
}
});
if (!is_started()) {
// Initialize the wait set before starting.
init_wait_set();
// Start the listener thread.
@@ -122,7 +108,7 @@ GraphListener::run_loop()
{
while (true) {
// If shutdown() was called, exit.
if (is_shutdown_.load()) {
if (is_shutdown()) {
return;
}
rcl_ret_t ret;
@@ -190,7 +176,7 @@ GraphListener::run_loop()
if (graph_gc == wait_set_.guard_conditions[graph_gc_indexes[i]]) {
node_ptr->notify_graph_change();
}
if (is_shutdown_) {
if (is_shutdown()) {
// If shutdown, then notify the node of this as well.
node_ptr->notify_shutdown();
}
@@ -257,7 +243,7 @@ GraphListener::add_node(rclcpp::node_interfaces::NodeGraphInterface * node_graph
throw std::invalid_argument("node is nullptr");
}
std::lock_guard<std::mutex> shutdown_lock(shutdown_mutex_);
if (is_shutdown_.load()) {
if (is_shutdown()) {
throw GraphListenerShutdownError();
}
@@ -332,11 +318,11 @@ GraphListener::__shutdown()
{
std::lock_guard<std::mutex> shutdown_lock(shutdown_mutex_);
if (!is_shutdown_.exchange(true)) {
if (is_started_) {
if (is_started()) {
interrupt_(&interrupt_guard_condition_);
listener_thread_.join();
}
if (is_started_) {
if (is_started()) {
cleanup_wait_set();
}
}
@@ -365,6 +351,12 @@ GraphListener::shutdown(const std::nothrow_t &) noexcept
}
}
bool
GraphListener::is_started()
{
return is_started_;
}
bool
GraphListener::is_shutdown()
{

View File

@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <filesystem>
#include <memory>
#include <string>
#include <utility>
@@ -54,8 +55,8 @@ get_node_logger(const rcl_node_t * node)
return rclcpp::get_logger(logger_name);
}
rcpputils::fs::path
get_logging_directory()
std::filesystem::path
get_log_directory()
{
char * log_dir = NULL;
auto allocator = rcutils_get_default_allocator();

View File

@@ -547,6 +547,18 @@ Node::get_subscriptions_info_by_topic(const std::string & topic_name, bool no_ma
return node_graph_->get_subscriptions_info_by_topic(topic_name, no_mangle);
}
std::vector<rclcpp::ServiceEndpointInfo>
Node::get_clients_info_by_service(const std::string & service_name, bool no_mangle) const
{
return node_graph_->get_clients_info_by_service(service_name, no_mangle);
}
std::vector<rclcpp::ServiceEndpointInfo>
Node::get_servers_info_by_service(const std::string & service_name, bool no_mangle) const
{
return node_graph_->get_servers_info_by_service(service_name, no_mangle);
}
void
Node::for_each_callback_group(
const node_interfaces::NodeBaseInterface::CallbackGroupFunction & func)
@@ -689,7 +701,7 @@ Node::create_generic_client(
node_base_,
node_graph_,
node_services_,
service_name,
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
service_type,
qos,
group);

View File

@@ -132,6 +132,7 @@ NodeBase::NodeBase(
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Error in destruction of rosout publisher: %s", rcl_get_error_string().str);
rcl_reset_error();
}
}
}
@@ -139,6 +140,7 @@ NodeBase::NodeBase(
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Error in destruction of rcl node handle: %s", rcl_get_error_string().str);
rcl_reset_error();
}
delete node;
});
@@ -273,16 +275,6 @@ NodeBase::get_associated_with_executor_atomic()
return associated_with_executor_;
}
rclcpp::GuardCondition &
NodeBase::get_notify_guard_condition()
{
std::lock_guard<std::recursive_mutex> notify_condition_lock(notify_guard_condition_mutex_);
if (!notify_guard_condition_is_valid_) {
throw std::runtime_error("failed to get notify guard condition because it is invalid");
}
return *notify_guard_condition_;
}
rclcpp::GuardCondition::SharedPtr
NodeBase::get_shared_notify_guard_condition()
{

View File

@@ -15,6 +15,7 @@
#include "rclcpp/node_interfaces/node_graph.hpp"
#include <algorithm>
#include <cstddef>
#include <map>
#include <string>
#include <tuple>
@@ -36,9 +37,6 @@ using rclcpp::graph_listener::GraphListener;
NodeGraph::NodeGraph(rclcpp::node_interfaces::NodeBaseInterface * node_base)
: node_base_(node_base),
graph_listener_(
node_base->get_context()->get_sub_context<GraphListener>(node_base->get_context())
),
should_add_to_graph_listener_(true),
graph_users_count_(0)
{}
@@ -50,7 +48,7 @@ NodeGraph::~NodeGraph()
// graph listener after checking that it was not here.
if (!should_add_to_graph_listener_.exchange(false)) {
// If it was already false, then it needs to now be removed.
graph_listener_->remove_node(this);
node_base_->get_context()->get_graph_listener()->remove_node(this);
}
}
@@ -419,7 +417,7 @@ NodeGraph::get_node_names_and_namespaces() const
rcl_get_error_string().str;
rcl_reset_error();
}
// TODO(karsten1987): Append rcutils_error_message once it's in master
RCUTILS_LOG_ERROR_NAMED("rclcpp", "%s", error_msg.c_str());
throw std::runtime_error(error_msg);
}
@@ -434,20 +432,15 @@ NodeGraph::get_node_names_and_namespaces() const
std::string error;
rcl_ret_t ret_names = rcutils_string_array_fini(&node_names_c);
if (ret_names != RCUTILS_RET_OK) {
// *INDENT-OFF*
// TODO(karsten1987): Append rcutils_error_message once it's in master
error = "could not destroy node names";
// *INDENT-ON*
error = std::string("could not destroy node names: ") + rcl_get_error_string().str;
}
rcl_ret_t ret_ns = rcutils_string_array_fini(&node_namespaces_c);
if (ret_ns != RCUTILS_RET_OK) {
// *INDENT-OFF*
// TODO(karsten1987): Append rcutils_error_message once it's in master
error += ", could not destroy node namespaces";
// *INDENT-ON*
error += std::string(", could not destroy node namespaces: ") + rcl_get_error_string().str;
}
if (ret_names != RCUTILS_RET_OK || ret_ns != RCUTILS_RET_OK) {
RCUTILS_LOG_ERROR_NAMED("rclcpp", "%s", error.c_str());
throw std::runtime_error(error);
}
@@ -603,8 +596,8 @@ NodeGraph::get_graph_event()
}
// on first call, add node to graph_listener_
if (should_add_to_graph_listener_.exchange(false)) {
graph_listener_->add_node(this);
graph_listener_->start_if_not_started();
node_base_->get_context()->get_graph_listener()->add_node(this);
node_base_->get_context()->get_graph_listener()->start_if_not_started();
}
return event;
}
@@ -761,6 +754,122 @@ NodeGraph::get_subscriptions_info_by_topic(
rcl_get_subscriptions_info_by_topic);
}
static
std::vector<rclcpp::ServiceEndpointInfo>
convert_to_service_info_list(const rcl_service_endpoint_info_array_t & info_array)
{
std::vector<rclcpp::ServiceEndpointInfo> service_info_list;
for (size_t i = 0; i < info_array.size; ++i) {
service_info_list.push_back(rclcpp::ServiceEndpointInfo(info_array.info_array[i]));
}
return service_info_list;
}
template<const char * EndpointType, typename FunctionT>
static std::vector<rclcpp::ServiceEndpointInfo>
get_info_by_service(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const std::string & service_name,
bool no_mangle,
FunctionT rcl_get_info_by_service)
{
std::string fqdn;
auto rcl_node_handle = node_base->get_rcl_node_handle();
if (no_mangle) {
fqdn = service_name;
} else {
fqdn = rclcpp::expand_topic_or_service_name(
service_name,
rcl_node_get_name(rcl_node_handle),
rcl_node_get_namespace(rcl_node_handle),
true);
// Get the node options
const rcl_node_options_t * node_options = rcl_node_get_options(rcl_node_handle);
if (nullptr == node_options) {
throw std::runtime_error("Need valid node options in get_info_by_service()");
}
const rcl_arguments_t * global_args = nullptr;
if (node_options->use_global_arguments) {
global_args = &(rcl_node_handle->context->global_arguments);
}
char * remapped_service_name = nullptr;
rcl_ret_t ret = rcl_remap_service_name(
&(node_options->arguments),
global_args,
fqdn.c_str(),
rcl_node_get_name(rcl_node_handle),
rcl_node_get_namespace(rcl_node_handle),
node_options->allocator,
&remapped_service_name);
if (RCL_RET_OK != ret) {
throw_from_rcl_error(ret, std::string("Failed to remap service name ") + fqdn);
} else if (nullptr != remapped_service_name) {
fqdn = remapped_service_name;
node_options->allocator.deallocate(remapped_service_name, node_options->allocator.state);
}
}
rcutils_allocator_t allocator = rcutils_get_default_allocator();
rcl_service_endpoint_info_array_t info_array =
rcl_get_zero_initialized_service_endpoint_info_array();
rcl_ret_t ret =
rcl_get_info_by_service(rcl_node_handle, &allocator, fqdn.c_str(), no_mangle, &info_array);
if (RCL_RET_OK != ret) {
auto error_msg =
std::string("Failed to get information by service for ") + EndpointType + std::string(":");
if (RCL_RET_UNSUPPORTED == ret) {
error_msg += std::string("function not supported by RMW_IMPLEMENTATION");
} else {
error_msg += rcl_get_error_string().str;
}
rcl_reset_error();
if (RCL_RET_OK != rcl_service_endpoint_info_array_fini(&info_array, &allocator)) {
error_msg += std::string(", failed also to cleanup service info array, leaking memory: ") +
rcl_get_error_string().str;
rcl_reset_error();
}
throw_from_rcl_error(ret, error_msg);
}
std::vector<rclcpp::ServiceEndpointInfo> service_info_list =
convert_to_service_info_list(info_array);
ret = rcl_service_endpoint_info_array_fini(&info_array, &allocator);
if (RCL_RET_OK != ret) {
throw_from_rcl_error(ret, "rcl_service_info_array_fini failed.");
}
return service_info_list;
}
static constexpr char kClientEndpointTypeName[] = "clients";
std::vector<rclcpp::ServiceEndpointInfo>
NodeGraph::get_clients_info_by_service(
const std::string & service_name,
bool no_mangle) const
{
return get_info_by_service<kClientEndpointTypeName>(
node_base_,
service_name,
no_mangle,
rcl_get_clients_info_by_service);
}
static constexpr char kServerEndpointTypeName[] = "servers";
std::vector<rclcpp::ServiceEndpointInfo>
NodeGraph::get_servers_info_by_service(
const std::string & service_name,
bool no_mangle) const
{
return get_info_by_service<kServerEndpointTypeName>(
node_base_,
service_name,
no_mangle,
rcl_get_servers_info_by_service);
}
std::string &
rclcpp::TopicEndpointInfo::node_name()
{
@@ -844,3 +953,99 @@ rclcpp::TopicEndpointInfo::topic_type_hash() const
{
return topic_type_hash_;
}
std::string &
rclcpp::ServiceEndpointInfo::node_name()
{
return node_name_;
}
const std::string &
rclcpp::ServiceEndpointInfo::node_name() const
{
return node_name_;
}
std::string &
rclcpp::ServiceEndpointInfo::node_namespace()
{
return node_namespace_;
}
const std::string &
rclcpp::ServiceEndpointInfo::node_namespace() const
{
return node_namespace_;
}
std::string &
rclcpp::ServiceEndpointInfo::service_type()
{
return service_type_;
}
const std::string &
rclcpp::ServiceEndpointInfo::service_type() const
{
return service_type_;
}
rclcpp::EndpointType &
rclcpp::ServiceEndpointInfo::endpoint_type()
{
return endpoint_type_;
}
const rclcpp::EndpointType &
rclcpp::ServiceEndpointInfo::endpoint_type() const
{
return endpoint_type_;
}
size_t &
rclcpp::ServiceEndpointInfo::endpoint_count()
{
return endpoint_count_;
}
const size_t &
rclcpp::ServiceEndpointInfo::endpoint_count() const
{
return endpoint_count_;
}
std::vector<std::array<uint8_t, RMW_GID_STORAGE_SIZE>> &
rclcpp::ServiceEndpointInfo::endpoint_gids()
{
return endpoint_gids_;
}
const std::vector<std::array<uint8_t, RMW_GID_STORAGE_SIZE>> &
rclcpp::ServiceEndpointInfo::endpoint_gids() const
{
return endpoint_gids_;
}
std::vector<rclcpp::QoS> &
rclcpp::ServiceEndpointInfo::qos_profiles()
{
return qos_profiles_;
}
const std::vector<rclcpp::QoS> &
rclcpp::ServiceEndpointInfo::qos_profiles() const
{
return qos_profiles_;
}
rosidl_type_hash_t &
rclcpp::ServiceEndpointInfo::service_type_hash()
{
return service_type_hash_;
}
const rosidl_type_hash_t &
rclcpp::ServiceEndpointInfo::service_type_hash() const
{
return service_type_hash_;
}

View File

@@ -192,6 +192,65 @@ format_range_reason(const std::string & name, const char * range_type)
return ss.str();
}
RCLCPP_LOCAL
rcl_interfaces::msg::SetParametersResult
__check_integer_range(
const rcl_interfaces::msg::ParameterDescriptor & descriptor,
const int64_t value)
{
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
auto integer_range = descriptor.integer_range.at(0);
if (value == integer_range.from_value || value == integer_range.to_value) {
return result;
}
if ((value < integer_range.from_value) || (value > integer_range.to_value)) {
result.successful = false;
result.reason = format_range_reason(descriptor.name, "integer");
return result;
}
if (integer_range.step == 0) {
return result;
}
if (((value - integer_range.from_value) % integer_range.step) == 0) {
return result;
}
result.successful = false;
result.reason = format_range_reason(descriptor.name, "integer");
return result;
}
RCLCPP_LOCAL
rcl_interfaces::msg::SetParametersResult
__check_double_range(
const rcl_interfaces::msg::ParameterDescriptor & descriptor,
const double value)
{
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
auto fp_range = descriptor.floating_point_range.at(0);
if (__are_doubles_equal(value, fp_range.from_value) || __are_doubles_equal(value,
fp_range.to_value))
{
return result;
}
if ((value < fp_range.from_value) || (value > fp_range.to_value)) {
result.successful = false;
result.reason = format_range_reason(descriptor.name, "floating point");
return result;
}
if (fp_range.step == 0.0) {
return result;
}
double rounded_div = std::round((value - fp_range.from_value) / fp_range.step);
if (__are_doubles_equal(value, fp_range.from_value + rounded_div * fp_range.step)) {
return result;
}
result.successful = false;
result.reason = format_range_reason(descriptor.name, "floating point");
return result;
}
RCLCPP_LOCAL
rcl_interfaces::msg::SetParametersResult
__check_parameter_value_in_range(
@@ -201,49 +260,39 @@ __check_parameter_value_in_range(
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
if (!descriptor.integer_range.empty() && value.get_type() == rclcpp::PARAMETER_INTEGER) {
int64_t v = value.get<int64_t>();
auto integer_range = descriptor.integer_range.at(0);
if (v == integer_range.from_value || v == integer_range.to_value) {
return result;
result = __check_integer_range(descriptor, value.get<int64_t>());
return result;
}
if (!descriptor.integer_range.empty() && value.get_type() == rclcpp::PARAMETER_INTEGER_ARRAY) {
std::vector<int64_t> val_array = value.get<std::vector<int64_t>>();
for (const int64_t & val : val_array) {
result = __check_integer_range(descriptor, val);
if (!result.successful) {
return result;
}
}
if ((v < integer_range.from_value) || (v > integer_range.to_value)) {
result.successful = false;
result.reason = format_range_reason(descriptor.name, "integer");
return result;
}
if (integer_range.step == 0) {
return result;
}
if (((v - integer_range.from_value) % integer_range.step) == 0) {
return result;
}
result.successful = false;
result.reason = format_range_reason(descriptor.name, "integer");
return result;
}
if (!descriptor.floating_point_range.empty() && value.get_type() == rclcpp::PARAMETER_DOUBLE) {
double v = value.get<double>();
auto fp_range = descriptor.floating_point_range.at(0);
if (__are_doubles_equal(v, fp_range.from_value) || __are_doubles_equal(v, fp_range.to_value)) {
return result;
}
if ((v < fp_range.from_value) || (v > fp_range.to_value)) {
result.successful = false;
result.reason = format_range_reason(descriptor.name, "floating point");
return result;
}
if (fp_range.step == 0.0) {
return result;
}
double rounded_div = std::round((v - fp_range.from_value) / fp_range.step);
if (__are_doubles_equal(v, fp_range.from_value + rounded_div * fp_range.step)) {
return result;
}
result.successful = false;
result.reason = format_range_reason(descriptor.name, "floating point");
result = __check_double_range(descriptor, value.get<double>());
return result;
}
if (!descriptor.floating_point_range.empty() &&
value.get_type() == rclcpp::PARAMETER_DOUBLE_ARRAY)
{
std::vector<double> val_array = value.get<std::vector<double>>();
for (const double & val : val_array) {
result = __check_double_range(descriptor, val);
if (!result.successful) {
return result;
}
}
return result;
}
return result;
}
@@ -1191,3 +1240,10 @@ NodeParameters::get_parameter_overrides() const
{
return parameter_overrides_;
}
void
NodeParameters::enable_parameter_modification()
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
parameter_modification_enabled_ = true;
}

View File

@@ -65,11 +65,11 @@ public:
: logger_(node_logging->get_logger()),
node_base_(node_base)
{
rclcpp::ParameterValue enable_param;
const std::string enable_param_name = "start_type_description_service";
bool enabled = false;
try {
auto enable_param = node_parameters->declare_parameter(
if (!node_parameters->has_parameter(enable_param_name)) {
enable_param = node_parameters->declare_parameter(
enable_param_name,
rclcpp::ParameterValue(true),
rcl_interfaces::msg::ParameterDescriptor()
@@ -77,13 +77,21 @@ public:
.set__type(rclcpp::PARAMETER_BOOL)
.set__description("Start the ~/get_type_description service for this node.")
.set__read_only(true));
enabled = enable_param.get<bool>();
} catch (const rclcpp::exceptions::InvalidParameterTypeException & exc) {
RCLCPP_ERROR(logger_, "%s", exc.what());
throw;
} else {
enable_param = node_parameters->get_parameter(enable_param_name).get_parameter_value();
}
if (enable_param.get_type() != rclcpp::PARAMETER_BOOL) {
RCLCPP_ERROR(
logger_,
"Invalid type '%s' for parameter 'start_type_description_service', should be 'bool'",
rclcpp::to_string(enable_param.get_type()).c_str());
std::ostringstream ss;
ss << "Wrong parameter type, parameter {" << enable_param_name << "} is of type {bool}, "
<< "setting it to {" << to_string(enable_param.get_type()) << "} is not allowed.";
throw rclcpp::exceptions::InvalidParameterTypeException(enable_param_name, ss.str());
}
if (enabled) {
if (enable_param.get<bool>()) {
auto * rcl_node = node_base->get_rcl_node_handle();
std::shared_ptr<rcl_service_t> rcl_srv(
new rcl_service_t,
@@ -105,6 +113,7 @@ public:
RCLCPP_ERROR(
logger_, "Failed to initialize ~/get_type_description service: %s",
rcl_get_error_string().str);
rcl_reset_error();
throw std::runtime_error(
"Failed to initialize ~/get_type_description service.");
}

View File

@@ -80,6 +80,7 @@ NodeOptions::operator=(const NodeOptions & other)
this->clock_type_ = other.clock_type_;
this->clock_qos_ = other.clock_qos_;
this->use_clock_thread_ = other.use_clock_thread_;
this->enable_logger_service_ = other.enable_logger_service_;
this->parameter_event_qos_ = other.parameter_event_qos_;
this->rosout_qos_ = other.rosout_qos_;
this->parameter_event_publisher_options_ = other.parameter_event_publisher_options_;

View File

@@ -28,6 +28,9 @@ ParameterEventsFilter::ParameterEventsFilter(
const std::vector<EventType> & types)
: event_(event)
{
if (!event) {
throw std::invalid_argument("event cannot be null");
}
if (std::find(types.begin(), types.end(), EventType::NEW) != types.end()) {
for (auto & new_parameter : event->new_parameters) {
if (std::find(names.begin(), names.end(), new_parameter.name) != names.end()) {

View File

@@ -81,7 +81,15 @@ rclcpp::parameter_map_from(const rcl_params_t * const c_params, const char * nod
throw InvalidParametersException(message);
}
const rcl_variant_t * const c_param_value = &(c_params_node->parameter_values[p]);
params_node.emplace_back(c_param_name, parameter_value_from(c_param_value));
ParameterValue value;
try {
value = parameter_value_from(c_param_value);
} catch (const InvalidParameterValueException & e) {
throw InvalidParameterValueException(
std::string("parameter_value_from failed for parameter '") +
c_param_name + "': " + e.what());
}
params_node.emplace_back(c_param_name, value);
}
}

View File

@@ -135,15 +135,28 @@ void
PublisherBase::bind_event_callbacks(
const PublisherEventCallbacks & event_callbacks, bool use_default_callbacks)
{
if (event_callbacks.deadline_callback) {
this->add_event_handler(
event_callbacks.deadline_callback,
RCL_PUBLISHER_OFFERED_DEADLINE_MISSED);
try {
if (event_callbacks.deadline_callback) {
this->add_event_handler(
event_callbacks.deadline_callback,
RCL_PUBLISHER_OFFERED_DEADLINE_MISSED);
}
} catch (const UnsupportedEventTypeException & /*exc*/) {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for deadline; not supported");
}
if (event_callbacks.liveliness_callback) {
this->add_event_handler(
event_callbacks.liveliness_callback,
RCL_PUBLISHER_LIVELINESS_LOST);
try {
if (event_callbacks.liveliness_callback) {
this->add_event_handler(
event_callbacks.liveliness_callback,
RCL_PUBLISHER_LIVELINESS_LOST);
}
} catch (const UnsupportedEventTypeException & /*exc*/) {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for liveliness; not supported");
}
QOSOfferedIncompatibleQoSCallbackType incompatible_qos_cb;
@@ -160,9 +173,9 @@ PublisherBase::bind_event_callbacks(
this->add_event_handler(incompatible_qos_cb, RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
}
} catch (const UnsupportedEventTypeException & /*exc*/) {
RCLCPP_DEBUG(
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for incompatible qos; wrong callback type");
"Failed to add event handler for incompatible qos; not supported");
}
IncompatibleTypeCallbackType incompatible_type_cb;
@@ -179,14 +192,21 @@ PublisherBase::bind_event_callbacks(
this->add_event_handler(incompatible_type_cb, RCL_PUBLISHER_INCOMPATIBLE_TYPE);
}
} catch (UnsupportedEventTypeException & /*exc*/) {
RCLCPP_DEBUG(
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for incompatible type; wrong callback type");
"Failed to add event handler for incompatible type; not supported");
}
if (event_callbacks.matched_callback) {
this->add_event_handler(
event_callbacks.matched_callback,
RCL_PUBLISHER_MATCHED);
try {
if (event_callbacks.matched_callback) {
this->add_event_handler(
event_callbacks.matched_callback,
RCL_PUBLISHER_MATCHED);
}
} catch (const UnsupportedEventTypeException & /*exc*/) {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for matched; not supported");
}
}
@@ -347,10 +367,8 @@ PublisherBase::default_incompatible_qos_callback(
void
PublisherBase::default_incompatible_type_callback(
rclcpp::IncompatibleTypeInfo & event) const
[[maybe_unused]] rclcpp::IncompatibleTypeInfo & event) const
{
(void)event;
RCLCPP_WARN(
rclcpp::get_logger(rcl_node_get_logger_name(rcl_node_handle_.get())),
"Incompatible type on topic '%s', no messages will be sent to it.", get_topic_name());

View File

@@ -69,8 +69,10 @@ QoSInitialization::from_rmw(const rmw_qos_profile_t & rmw_qos)
return KeepLast(rmw_qos.depth, false);
case RMW_QOS_POLICY_HISTORY_KEEP_LAST:
case RMW_QOS_POLICY_HISTORY_UNKNOWN:
default:
return KeepLast(rmw_qos.depth);
default:
throw std::invalid_argument(
"Invalid history policy enum value passed to QoSInitialization::from_rmw");
}
}
@@ -407,7 +409,7 @@ ParameterEventsQoS::ParameterEventsQoS(const QoSInitialization & qos_initializat
{}
RosoutQoS::RosoutQoS(const QoSInitialization & rosout_initialization)
: QoS(rosout_initialization, rcl_qos_profile_rosout_default)
: QoS(rosout_initialization, rmw_qos_profile_rosout_default)
{}
SystemDefaultsQoS::SystemDefaultsQoS(const QoSInitialization & qos_initialization)

View File

@@ -67,16 +67,16 @@ Rate::sleep()
// Calculate the time to sleep
auto time_to_sleep = next_interval - now;
// Sleep (will get interrupted by ctrl-c, may not sleep full time)
clock_->sleep_for(time_to_sleep);
try {
// If the context is invalid, an exception will be thrown.
clock_->sleep_for(time_to_sleep);
} catch (const std::runtime_error & e) {
// If it didn't sleep the full time, return false
return false;
}
return true;
}
bool
Rate::is_steady() const
{
return clock_->get_clock_type() == RCL_STEADY_TIME;
}
rcl_clock_type_t
Rate::get_type() const
{

View File

@@ -36,7 +36,6 @@ SerializationBase::SerializationBase(const rosidl_message_type_support_t * type_
void SerializationBase::serialize_message(
const void * ros_message, SerializedMessage * serialized_message) const
{
rcpputils::check_true(nullptr != type_support_, "Typesupport is nullpointer.");
rcpputils::check_true(nullptr != ros_message, "ROS message is nullpointer.");
rcpputils::check_true(nullptr != serialized_message, "Serialized message is nullpointer.");
@@ -52,7 +51,6 @@ void SerializationBase::serialize_message(
void SerializationBase::deserialize_message(
const SerializedMessage * serialized_message, void * ros_message) const
{
rcpputils::check_true(nullptr != type_support_, "Typesupport is nullpointer.");
rcpputils::check_true(nullptr != serialized_message, "Serialized message is nullpointer.");
rcpputils::check_true(
0u != serialized_message->capacity(),

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