Compare commits

..

44 Commits

Author SHA1 Message Date
Alejandro Hernandez Cordero
04f85067e8 29.5.7 2026-02-09 13:36:00 +01:00
Alejandro Hernandez Cordero
70f9ed58d2 Changelog
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2026-02-09 13:35:54 +01:00
mergify[bot]
e2af9da76c include the 1st spin that might throw the exception. (#3042) (#3044)
(cherry picked from commit 5ac7f1f024)

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2026-02-02 12:37:44 +01:00
mergify[bot]
880d89e583 print warning message on owner node if the parameter operation fails. (#3037) (#3038)
(cherry picked from commit f8a7ace7a8)

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2026-01-30 15:13:40 +01:00
mergify[bot]
810ff6a8d6 remove test_static_executor_entities_collector.cpp (#3041) (#3045)
(cherry picked from commit db7469798f)

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2026-01-30 15:04:04 +09:00
mergify[bot]
7e4e72c70d fix context in wait for message wait set (#3030) (#3031)
(cherry picked from commit fcc505f453)

Signed-off-by: Rahat Dhande <rahatchd@gmail.com>
Co-authored-by: Rahat Dhande <rahatchd@gmail.com>
2026-01-23 16:46:35 +01:00
mergify[bot]
d5d4f6c44c Update exception documentation for goal cancellation in ServerGoalHandle (#3019) (#3022)
* Update exception documentation for goal cancellation

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


(cherry picked from commit 6397047d47)

Signed-off-by: Andrei Costinescu <AndreiCostinescu@users.noreply.github.com>
Co-authored-by: Andrei Costinescu <AndreiCostinescu@users.noreply.github.com>
2026-01-21 10:22:38 +01:00
mergify[bot]
19e443bce9 Improve the robustness of the TopicEndpointInfo constructor (#3013) (#3014)
(cherry picked from commit 7f783cbf58)

Signed-off-by: Barry Xu <barry.xu@sony.com>
Co-authored-by: Barry Xu <barry.xu@sony.com>
2026-01-12 15:36:33 +01:00
Alejandro Hernandez Cordero
4551b69f6e 29.5.6 2025-12-23 11:22:23 +01:00
Alejandro Hernandez Cordero
785b45a2fc Changelog
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-12-23 11:22:17 +01:00
mergify[bot]
c5b427c2ec Unified Node Interfaces: Add const version of get_node_x_interface() (#3006) (#3008)
(cherry picked from commit 825b4e4650)

Signed-off-by: Fabian Hirmann <f.hirmann@arti-robots.com>
Co-authored-by: fabianhirmann <117293434+fabianhirmann@users.noreply.github.com>
2025-12-18 22:21:01 +01:00
Tomoya Fujita
3ce946f6e9 remove I/O from signal handler. (#3000)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-12-04 10:00:50 +01:00
mergify[bot]
ebb6175dfa correct test function descriptions (#2970) (#2992)
(cherry picked from commit 354413c060)

Signed-off-by: Yuchen Liu <lyuchen9696@gmail.com>
Co-authored-by: Yuchen966 <70603129+Yuchen966@users.noreply.github.com>
2025-11-18 16:17:05 +01:00
Alejandro Hernandez Cordero
fc13cfe5fe 29.5.5 2025-11-18 14:49:13 +01:00
Alejandro Hernandez Cordero
331bcb2ec9 Changelog
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-11-18 14:49:07 +01:00
mergify[bot]
4db3e3303b Fix REP url locations (#2987) (#2989)
This popped up in my global replace


(cherry picked from commit ad019b9827)

Signed-off-by: Tim Clephas <tim.clephas@nobleo.nl>
Co-authored-by: Tim Clephas <tim.clephas@nobleo.nl>
2025-11-17 10:09:04 +01:00
mergify[bot]
bda164fb4d Add get_parameter_or overload returning value or alternative (#2973) (#2976)
(cherry picked from commit eb49444c32)

Signed-off-by: Zheng Qu <quzhengrobot@gmail.com>
Co-authored-by: Zheng Qu <quzhengrobot@gmail.com>
2025-11-10 08:54:59 +01:00
Alejandro Hernandez Cordero
a35bc62b8c 29.5.4 2025-10-21 11:48:59 +02:00
Alejandro Hernandez Cordero
8a9f0468e3 Changelog
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-10-21 11:48:54 +02:00
mergify[bot]
6a2d90ebf8 it misses the iterator second to lock the weakptr. (#2958) (#2959)
(cherry picked from commit aa60fcf22a)

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-09-30 15:42:35 +02:00
Alejandro Hernandez Cordero
c21065e979 29.5.3 2025-09-11 15:32:55 +02:00
Alejandro Hernandez Cordero
c4ee11a5c7 Changelog
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-09-11 15:32:51 +02:00
mergify[bot]
14ecbc3f0b Fix: improve exception context for parameter_value_from (#2917) (#2919)
(cherry picked from commit 1f2adc9829)

Signed-off-by: Michiel Leegwater <mleegwt@users.noreply.github.com>
Signed-off-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
Co-authored-by: Michiel Leegwater <mleegwt@users.noreply.github.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2025-08-18 19:59:13 +02:00
Tim Clephas
8a4cb48b2c Allow for implicitly convertable loggers as well (#2922) (#2936)
Signed-off-by: Tim Clephas <tim.clephas@nobleo.nl>
2025-08-18 13:59:13 +02:00
mergify[bot]
aa634b28df Clearer warning message, the old one lacked information and was perhaps misleading (#2927) (#2931)
* change misleading warning message, making it more correct and informative



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



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



---------


(cherry picked from commit 37677791ca)

Signed-off-by: Peter Mitrano (AR) <peter.mitrano@agile-robots.com>
Co-authored-by: Peter Mitrano (AR) <peter.mitrano@agile-robots.com>
2025-08-13 10:37:17 +02:00
mergify[bot]
8ec31edd4a fix cmake deprecation (#2914) (#2915)
cmake version < then 3.10 is deprecated


(cherry picked from commit 6392ee5187)

Signed-off-by: Mos <realeandrea@yahoo.it>
Co-authored-by: mosfet80 <10235105+mosfet80@users.noreply.github.com>
2025-07-24 17:01:57 +02:00
mergify[bot]
a709d81a93 Fix start_type_description_service param handling (#2897) (#2908)
* Fix `start_type_description_service` param handling



* Add test



* Demonstrate different exceptions depending on node options



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



* Uncrustify



---------


(cherry picked from commit 4fb558ae7b)

Signed-off-by: Patrick Roncagliolo <ronca.pat@gmail.com>
Co-authored-by: Patrick Roncagliolo <ronca.pat@gmail.com>
2025-07-16 21:53:03 -07:00
mergify[bot]
a35793ad28 Add qos parameter for wait_for_message function (#2903) (#2905)
(cherry picked from commit 2fcef70ea7)

Signed-off-by: Sriharsha Ghanta <ghanta1996@gmail.com>
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
Co-authored-by: Sriharsha Ghanta <ghanta_sriharsha@mymail.sutd.edu.sg>
Co-authored-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-07-16 15:51:14 -07:00
mergify[bot]
7cba3c4882 Expose typesupport_helpers API needed for the Rosbag2 (#2858) (#2901)
* 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



* Use C++ style in doxygen documentation



---------


(cherry picked from commit 448287b109)

Signed-off-by: Michael Orlov <michael.orlov@apex.ai>
Co-authored-by: Michael Orlov <morlovmr@gmail.com>
2025-07-13 23:17:31 -07:00
mergify[bot]
27e800b910 Fujitatomoya/test append parameter override (#2896) (#2899)
(cherry picked from commit 84c6fb1cfc)

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-07-10 09:21:48 +02:00
mergify[bot]
e6f6b2a7ad Add overload of append_parameter_override (#2891) (#2894)
(cherry picked from commit fa0cf2da31)

Signed-off-by: Patrick Roncagliolo <ronca.pat@gmail.com>
Co-authored-by: Patrick Roncagliolo <ronca.pat@gmail.com>
2025-07-09 14:03:59 -07:00
Scott K Logan
6c95d10cca 29.5.2 2025-07-07 16:06:10 -05:00
mergify[bot]
a5a7febb60 Shutdown deadlock fix jazzy (#2887) (#2888)
* fix: Don't deadlock if removing shutdown callbacks in a shutdown callback



* refactor: Made fix API compatible



---------



(cherry picked from commit 7aab9b6f99)

Signed-off-by: Janosch Machowinski <J.Machowinski@cellumation.com>
Co-authored-by: Janosch Machowinski <jmachowinski@users.noreply.github.com>
Co-authored-by: Janosch Machowinski <J.Machowinski@cellumation.com>
2025-07-03 08:30:37 +02:00
mergify[bot]
7373669455 fix test_publisher_with_system_default_qos. (#2881) (#2884)
(cherry picked from commit e6577c6792)

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-06-26 22:58:08 +02:00
Alejandro Hernandez Cordero
ae930aa2e5 29.5.1 2025-06-23 16:45:44 +02:00
Alejandro Hernandez Cordero
24846c3109 Changelog
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-06-23 16:45:40 +02:00
mergify[bot]
160da7b432 Removed warning test_qos (#2859) (#2873)
(cherry picked from commit df3a303a17)

Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
Co-authored-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2025-06-13 08:59:48 +02:00
mergify[bot]
22939ddf9b Fix for memory leaks in rclcpp::SerializedMessage (#2861) (#2863)
(cherry picked from commit 8d44b95d8b)

Signed-off-by: Michael Orlov <morlovmr@gmail.com>
Signed-off-by: Michael Orlov <michael.orlov@apex.ai>
Co-authored-by: Michael Orlov <morlovmr@gmail.com>
Co-authored-by: kylemarcey <marcey.kyle@gmail.com>
2025-05-30 22:17:14 +02:00
mergify[bot]
ea1d764f42 Replace std::default_random_engine with std::mt19937 (rolling) (#2843) (#2866)
(cherry picked from commit db8d917a12)

Signed-off-by: keeponoiro <keeeeeeep@gmail.com>
Co-authored-by: keeponoiro <keeeeeeep@gmail.com>
2025-05-30 10:49:59 +02:00
mergify[bot]
82666affcd get_all_data_impl() does not handle null pointers properly, causing segmentation fault (backport #2840) (#2850)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-05-26 18:29:37 +02:00
mergify[bot]
0be3acf32f Added missing chrono includes (#2854) (#2855)
(cherry picked from commit 373a63c5e6)

Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
Co-authored-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2025-05-26 13:25:57 +02:00
mergify[bot]
34005e903f QoSInitialization::from_rmw does not validate invalid history policy values, leading to silent failures (#2841) (#2846)
(cherry picked from commit 73e9bfb62b)

Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
Co-authored-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2025-05-19 08:57:33 +02:00
mergify[bot]
288be9c981 Add missing 's' to 'NodeParametersInterface' in doc/comment (#2831) (#2833)
(cherry picked from commit b1ec85df16)

Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
Co-authored-by: Christophe Bedard <bedard.christophe@gmail.com>
2025-04-30 10:10:19 -07:00
mergify[bot]
93028ff38d subordinate node consistent behavior and update docstring. (#2822) (#2830)
* subordinate node consistent behavior and update docstring.



* add subnode_parameter_operation test.



* typo fixes.



---------


(cherry picked from commit c89a2b1013)

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-04-29 20:26:22 -07:00
97 changed files with 1748 additions and 2892 deletions

View File

@@ -2,67 +2,59 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30.1.2 (2025-10-21)
29.5.7 (2026-02-09)
-------------------
* 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
* include the 1st spin that might throw the exception. (`#3042 <https://github.com/ros2/rclcpp/issues/3042>`_) (`#3044 <https://github.com/ros2/rclcpp/issues/3044>`_)
* print warning message on owner node if the parameter operation fails. (`#3037 <https://github.com/ros2/rclcpp/issues/3037>`_) (`#3038 <https://github.com/ros2/rclcpp/issues/3038>`_)
* remove test_static_executor_entities_collector.cpp (`#3041 <https://github.com/ros2/rclcpp/issues/3041>`_) (`#3045 <https://github.com/ros2/rclcpp/issues/3045>`_)
* fix context in wait for message wait set (`#3030 <https://github.com/ros2/rclcpp/issues/3030>`_) (`#3031 <https://github.com/ros2/rclcpp/issues/3031>`_)
* Improve the robustness of the TopicEndpointInfo constructor (`#3013 <https://github.com/ros2/rclcpp/issues/3013>`_) (`#3014 <https://github.com/ros2/rclcpp/issues/3014>`_)
* Contributors: mergify[bot]
30.1.1 (2025-09-11)
29.5.6 (2025-12-23)
-------------------
* 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
* Unified Node Interfaces: Add const version of get_node_x_interface() (`#3006 <https://github.com/ros2/rclcpp/issues/3006>`_) (`#3008 <https://github.com/ros2/rclcpp/issues/3008>`_)
* remove I/O from signal handler. (`#3000 <https://github.com/ros2/rclcpp/issues/3000>`_)
* correct test function descriptions (`#2970 <https://github.com/ros2/rclcpp/issues/2970>`_) (`#2992 <https://github.com/ros2/rclcpp/issues/2992>`_)
* Contributors: Tomoya Fujita, mergify[bot]
30.1.0 (2025-07-29)
29.5.5 (2025-11-18)
-------------------
* 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
* Fix REP url locations (`#2987 <https://github.com/ros2/rclcpp/issues/2987>`_) (`#2989 <https://github.com/ros2/rclcpp/issues/2989>`_)
* Contributors: mergify[bot]
30.0.0 (2025-07-01)
29.5.4 (2025-10-21)
-------------------
* 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)
29.5.3 (2025-09-11)
-------------------
* 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
* Fix: improve exception context for parameter_value_from (`#2917 <https://github.com/ros2/rclcpp/issues/2917>`_) (`#2919 <https://github.com/ros2/rclcpp/issues/2919>`_)
* Allow for implicitly convertable loggers as well (`#2922 <https://github.com/ros2/rclcpp/issues/2922>`_) (`#2936 <https://github.com/ros2/rclcpp/issues/2936>`_)
* Fix `start_type_description_service` param handling (`#2897 <https://github.com/ros2/rclcpp/issues/2897>`_) (`#2908 <https://github.com/ros2/rclcpp/issues/2908>`_)
* Add qos parameter for wait_for_message function (`#2903 <https://github.com/ros2/rclcpp/issues/2903>`_) (`#2905 <https://github.com/ros2/rclcpp/issues/2905>`_)
* Expose `typesupport_helpers` API needed for the Rosbag2 (`#2858 <https://github.com/ros2/rclcpp/issues/2858>`_) (`#2901 <https://github.com/ros2/rclcpp/issues/2901>`_)
* Fujitatomoya/test append parameter override (`#2896 <https://github.com/ros2/rclcpp/issues/2896>`_) (`#2899 <https://github.com/ros2/rclcpp/issues/2899>`_)
* Add overload of `append_parameter_override` (`#2891 <https://github.com/ros2/rclcpp/issues/2891>`_) (`#2894 <https://github.com/ros2/rclcpp/issues/2894>`_)
* Contributors: Tim Clephas, mergify[bot]
29.6.0 (2025-04-25)
29.5.2 (2025-07-07)
-------------------
* Shutdown deadlock fix jazzy (`#2887 <https://github.com/ros2/rclcpp/issues/2887>`_) (`#2888 <https://github.com/ros2/rclcpp/issues/2888>`_)
* Fix test_publisher_with_system_default_qos (`#2881 <https://github.com/ros2/rclcpp/issues/2881>`_) (`#2884 <https://github.com/ros2/rclcpp/issues/2884>`_)
* Contributors: Tomoya Fujita, Janosch Machowinski
29.5.1 (2025-06-23)
-------------------
* Removed warning test_qos (`#2859 <https://github.com/ros2/rclcpp/issues/2859>`_) (`#2873 <https://github.com/ros2/rclcpp/issues/2873>`_)
* Fix for memory leaks in rclcpp::SerializedMessage (`#2861 <https://github.com/ros2/rclcpp/issues/2861>`_) (`#2863 <https://github.com/ros2/rclcpp/issues/2863>`_)
* get_all_data_impl() does not handle null pointers properly, causing segmentation fault (backport `#2840 <https://github.com/ros2/rclcpp/issues/2840>`_) (`#2850 <https://github.com/ros2/rclcpp/issues/2850>`_)
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_) (`#2855 <https://github.com/ros2/rclcpp/issues/2855>`_)
* QoSInitialization::from_rmw does not validate invalid history policy values, leading to silent failures (`#2841 <https://github.com/ros2/rclcpp/issues/2841>`_) (`#2846 <https://github.com/ros2/rclcpp/issues/2846>`_)
* Add missing 's' to 'NodeParametersInterface' in doc/comment (`#2831 <https://github.com/ros2/rclcpp/issues/2831>`_) (`#2833 <https://github.com/ros2/rclcpp/issues/2833>`_)
* subordinate node consistent behavior and update docstring. (`#2822 <https://github.com/ros2/rclcpp/issues/2822>`_) (`#2830 <https://github.com/ros2/rclcpp/issues/2830>`_)
* 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
* Contributors: Alejandro Hernández Cordero, Tomoya Fujita, mergify[bot]
29.5.0 (2025-04-18)
-------------------

View File

@@ -70,6 +70,7 @@ 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
@@ -146,6 +147,27 @@ 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,22 +21,6 @@ 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

@@ -200,6 +200,21 @@ public:
bool
ros_time_is_active();
/**
* Deprecated. This API is broken, as there is no way to get a deep
* copy of a clock. Therefore one can experience spurious wakeups triggered
* by some other instance of a clock.
*
* 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.
*/
[[deprecated("Use ClockConditionalVariable")]]
RCLCPP_PUBLIC
void
cancel_sleep_or_wait();
/// Return the rcl_clock_t clock handle
RCLCPP_PUBLIC
rcl_clock_t *

View File

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

@@ -371,9 +371,6 @@ 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

View File

@@ -20,6 +20,7 @@
#include "rclcpp/executors/multi_threaded_executor.hpp"
#include "rclcpp/executors/single_threaded_executor.hpp"
#include "rclcpp/executors/static_single_threaded_executor.hpp"
#include "rclcpp/experimental/executors/events_executor/events_executor.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/utilities.hpp"
@@ -28,82 +29,24 @@
namespace rclcpp
{
/**
* @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")]]
/// Create a default single-threaded executor and execute all available work exhaustively.
/** \param[in] node_ptr Shared pointer to the node to spin. */
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);
/**
* @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")]]
/// Create a default single-threaded executor and execute any immediately available work.
/** \param[in] node_ptr Shared pointer to the node to spin. */
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

@@ -0,0 +1,145 @@
// 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 contains some performance optimization to avoid unnecessary reconstructions of
* 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.
* This executor is deprecated because these performance improvements have now been
* applied to all other executors.
* This executor is also considered unstable due to known bugs.
* See the unit-tests that are only applied to `StandardExecutors` for information
* on the known limitations.
*
* 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 [[deprecated("Use rclcpp::executors::SingleThreadedExecutor")]] 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,8 +178,6 @@ public:
void clear() override
{
TRACETOOLS_TRACEPOINT(rclcpp_ring_buffer_clear, static_cast<const void *>(this));
std::lock_guard<std::mutex> lock(mutex_);
clear_();
}
private:
@@ -229,14 +227,6 @@ 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 {};
@@ -306,7 +296,7 @@ private:
return {};
}
const size_t capacity_;
size_t capacity_;
std::vector<BufferT> ring_buffer_;

View File

@@ -64,17 +64,17 @@ public:
/// 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
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);
bool execute_timers_separate_thread = false,
const rclcpp::ExecutorOptions & options = rclcpp::ExecutorOptions());
/// Default destructor.
RCLCPP_PUBLIC

View File

@@ -154,12 +154,6 @@ 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
@@ -187,6 +181,7 @@ 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

@@ -78,6 +78,34 @@ RCLCPP_PUBLIC
Logger
get_node_logger(const rcl_node_t * node);
// TODO(ahcorde): Remove deprecated class on the next release (in Rolling after Kilted).
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
/// Get the current logging directory.
/**
* For more details of how the logging directory is determined,
* see rcl_logging_get_logging_directory().
*
* \returns the logging directory being used.
* \throws rclcpp::exceptions::RCLError if an unexpected error occurs.
*/
[[deprecated("use rclcpp::get_log_directory instead of rclcpp::get_logging_directory")]]
RCLCPP_PUBLIC
rcpputils::fs::path
get_logging_directory();
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
/// Get the current logging directory.
/**
* For more details of how the logging directory is determined,

View File

@@ -1,983 +0,0 @@
// 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

@@ -199,6 +199,12 @@ init_tuple(NodeT & n)
{ \
return StorageClassT::template get<NodeInterfaceType>(); \
} \
\
std::shared_ptr<const NodeInterfaceType> \
get_node_ ## NodeInterfaceName ## _interface() const \
{ \
return StorageClassT::template get<NodeInterfaceType>(); \
} \
}; \
} // namespace rclcpp::node_interfaces::detail
// *INDENT-ON*

View File

@@ -121,6 +121,11 @@ 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,6 +144,17 @@ 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

@@ -165,6 +165,8 @@ private:
/// 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

@@ -53,13 +53,17 @@ public:
/// Construct a TopicEndpointInfo from a rcl_topic_endpoint_info_t.
RCLCPP_PUBLIC
explicit TopicEndpointInfo(const rcl_topic_endpoint_info_t & info)
: node_name_(info.node_name),
node_namespace_(info.node_namespace),
topic_type_(info.topic_type),
endpoint_type_(static_cast<rclcpp::EndpointType>(info.endpoint_type)),
: endpoint_type_(static_cast<rclcpp::EndpointType>(info.endpoint_type)),
qos_profile_({info.qos_profile.history, info.qos_profile.depth}, info.qos_profile),
topic_type_hash_(info.topic_type_hash)
{
if (!info.node_name || !info.node_namespace || !info.topic_type) {
throw std::invalid_argument("Constructor TopicEndpointInfo with invalid topic endpoint info");
}
node_name_ = info.node_name;
node_namespace_ = info.node_namespace;
topic_type_ = info.topic_type;
std::copy(info.endpoint_gid, info.endpoint_gid + RMW_GID_STORAGE_SIZE, endpoint_gid_.begin());
}

View File

@@ -574,13 +574,6 @@ 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

@@ -68,6 +68,8 @@
*
* - 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

@@ -33,11 +33,12 @@ class Time
public:
/// Time constructor
/**
* 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.
* 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.
*
* \param seconds the seconds component, valid only if positive
* \param nanoseconds the nanoseconds component, to be added to the seconds component
* \param seconds part of the time in seconds since time epoch
* \param nanoseconds part of the time in nanoseconds since time epoch
* \param clock_type clock type
* \throws std::runtime_error if seconds are negative
*/
@@ -46,7 +47,7 @@ public:
/// Time constructor
/**
* \param nanoseconds the total time since the epoch in nanoseconds
* \param nanoseconds since time epoch
* \param clock_type clock type
* \throws std::runtime_error if nanoseconds are negative
*/
@@ -189,7 +190,7 @@ public:
/// Get the nanoseconds since epoch
/**
* \return the total time since the epoch in nanoseconds, as a rcl_time_point_value_t structure.
* \return the nanoseconds since epoch as a rcl_time_point_value_t structure.
*/
RCLCPP_PUBLIC
rcl_time_point_value_t
@@ -208,7 +209,7 @@ public:
* \warning Depending on sizeof(double) there could be significant precision loss.
* When an exact time is required use nanoseconds() instead.
*
* \return the total time since the epoch in seconds, as a floating point number.
* \return the seconds since epoch as a floating point number.
*/
RCLCPP_PUBLIC
double

View File

@@ -16,7 +16,6 @@
#define RCLCPP__TYPE_ADAPTER_HPP_
#include <type_traits>
#include <new>
namespace rclcpp
{
@@ -129,24 +128,6 @@ 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

@@ -56,7 +56,7 @@ bool wait_for_message(
}
});
rclcpp::WaitSet wait_set;
rclcpp::WaitSet wait_set({}, {}, {}, {}, {}, {}, context);
wait_set.add_subscription(subscription);
RCPPUTILS_SCOPE_EXIT(wait_set.remove_subscription(subscription); );
wait_set.add_guard_condition(gc);

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>30.1.2</version>
<version>29.5.7</version>
<description>The ROS client library in C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
@@ -17,7 +17,6 @@
<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

@@ -0,0 +1,164 @@
// 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_convertible_v<decltype(logger), ::rclcpp::Logger>, \
"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,6 +83,16 @@ 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,

View File

@@ -14,6 +14,7 @@
#include "rclcpp/context.hpp"
#include <map>
#include <memory>
#include <mutex>
#include <sstream>
@@ -28,7 +29,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"
@@ -142,12 +143,52 @@ rclcpp_logging_output_handler(
}
} // extern "C"
/**
* Global storage for pre and post shutdown recursive mutexes.
* Note, this is a ABI compatibility hack.
*/
class MutexLookup
{
std::mutex m;
struct MutexHolder
{
std::recursive_mutex on_shutdown_callbacks_mutex_;
std::recursive_mutex pre_shutdown_callbacks_mutex_;
};
std::map<const Context *, std::unique_ptr<MutexHolder>> mutexMap;
public:
MutexHolder & getMutexes(const Context *forContext)
{
auto it = mutexMap.find(forContext);
if(it == mutexMap.end()) {
it = mutexMap.emplace(forContext, std::make_unique<MutexHolder>()).first;
}
return *(it->second);
}
/**
* Only supposed to be called on deletion of context
*/
void removeMutexes(const Context *forContext)
{
mutexMap.erase(forContext);
}
};
MutexLookup mutexStorage;
Context::Context()
: rcl_context_(nullptr),
shutdown_reason_(""),
logging_mutex_(nullptr),
graph_listener_(nullptr)
{}
logging_mutex_(nullptr)
{
// allocate mutexes
mutexStorage.getMutexes(this);
}
Context::~Context()
{
@@ -166,6 +207,9 @@ Context::~Context()
} catch (...) {
RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "unhandled exception in ~Context()");
}
// delete mutexes
mutexStorage.removeMutexes(this);
}
RCLCPP_LOCAL
@@ -244,24 +288,6 @@ 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();
@@ -329,7 +355,8 @@ Context::shutdown(const std::string & reason)
// call each pre-shutdown callback
{
std::lock_guard<std::recursive_mutex> lock{pre_shutdown_callbacks_mutex_};
std::lock_guard<std::recursive_mutex> lock{mutexStorage.getMutexes(
this).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
@@ -351,7 +378,8 @@ Context::shutdown(const std::string & reason)
shutdown_reason_ = reason;
// call each shutdown callback
{
std::lock_guard<std::recursive_mutex> lock(on_shutdown_callbacks_mutex_);
std::lock_guard<std::recursive_mutex> lock(mutexStorage.getMutexes(
this).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
@@ -431,10 +459,12 @@ 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::recursive_mutex> lock(pre_shutdown_callbacks_mutex_);
std::lock_guard<std::recursive_mutex> lock(mutexStorage.getMutexes(
this).pre_shutdown_callbacks_mutex_);
pre_shutdown_callbacks_.emplace_back(callback_shared_ptr);
} else {
std::lock_guard<std::recursive_mutex> lock(on_shutdown_callbacks_mutex_);
std::lock_guard<std::recursive_mutex> lock(mutexStorage.getMutexes(
this).on_shutdown_callbacks_mutex_);
on_shutdown_callbacks_.emplace_back(callback_shared_ptr);
}
@@ -465,6 +495,7 @@ Context::remove_shutdown_callback(
return false;
}
callback_vector.erase(iter);
return true;
};
@@ -472,9 +503,11 @@ Context::remove_shutdown_callback(
shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
return remove_callback(pre_shutdown_callbacks_mutex_, pre_shutdown_callbacks_);
return remove_callback(mutexStorage.getMutexes(this).pre_shutdown_callbacks_mutex_,
pre_shutdown_callbacks_);
} else {
return remove_callback(on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
return remove_callback(mutexStorage.getMutexes(this).on_shutdown_callbacks_mutex_,
on_shutdown_callbacks_);
}
}
@@ -507,9 +540,11 @@ Context::get_shutdown_callback() const
shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
return get_callback_vector(pre_shutdown_callbacks_mutex_, pre_shutdown_callbacks_);
return get_callback_vector(mutexStorage.getMutexes(this).pre_shutdown_callbacks_mutex_,
pre_shutdown_callbacks_);
} else {
return get_callback_vector(on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
return get_callback_vector(mutexStorage.getMutexes(this).on_shutdown_callbacks_mutex_,
on_shutdown_callbacks_);
}
}
@@ -519,12 +554,6 @@ 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

@@ -18,7 +18,6 @@
#include <iterator>
#include <memory>
#include <map>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
@@ -53,7 +52,6 @@ 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)
@@ -188,11 +186,6 @@ Executor::add_callback_group(
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 {

View File

@@ -13,7 +13,6 @@
// limitations under the License.
#include "rclcpp/executors.hpp"
#include "rcpputils/compile_warnings.hpp"
void
rclcpp::spin_all(
@@ -26,6 +25,12 @@ 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)
{
@@ -35,6 +40,12 @@ 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)
{
@@ -51,19 +62,3 @@ 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

@@ -0,0 +1,223 @@
// 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)
{
// we need to make sure that callback groups don't get out of scope
// during the wait. As in jazzy, they are not covered by the DynamicStorage,
// we explicitly hold them here as a bugfix
std::vector<rclcpp::CallbackGroup::SharedPtr> cbgs;
if (this->entities_need_rebuild_.exchange(false) || current_collection_.empty()) {
this->collect_entities();
}
auto callback_groups = this->collector_.get_all_callback_groups();
cbgs.resize(callback_groups.size());
for(const auto & w_ptr : callback_groups) {
auto shr_ptr = w_ptr.lock();
if(shr_ptr) {
cbgs.push_back(std::move(shr_ptr));
}
}
auto wait_result = wait_set_.wait(std::chrono::nanoseconds(timeout));
// drop references to the callback groups, before trying to execute anything
cbgs.clear();
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)
bool execute_timers_separate_thread,
const rclcpp::ExecutorOptions & options)
: rclcpp::Executor(options)
{
// Get ownership of the queue used to store events.

View File

@@ -19,6 +19,7 @@
#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"
@@ -37,7 +38,8 @@ namespace graph_listener
{
GraphListener::GraphListener(const std::shared_ptr<Context> & parent_context)
: rcl_parent_context_(parent_context->get_rcl_context()),
: weak_parent_context_(parent_context),
rcl_parent_context_(parent_context->get_rcl_context()),
is_started_(false),
is_shutdown_(false),
interrupt_guard_condition_(parent_context)
@@ -70,11 +72,23 @@ void
GraphListener::start_if_not_started()
{
std::lock_guard<std::mutex> shutdown_lock(shutdown_mutex_);
if (is_shutdown()) {
if (is_shutdown_.load()) {
throw GraphListenerShutdownError();
}
if (!is_started()) {
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);
}
});
// Initialize the wait set before starting.
init_wait_set();
// Start the listener thread.
@@ -108,7 +122,7 @@ GraphListener::run_loop()
{
while (true) {
// If shutdown() was called, exit.
if (is_shutdown()) {
if (is_shutdown_.load()) {
return;
}
rcl_ret_t ret;
@@ -176,7 +190,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();
}
@@ -243,7 +257,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()) {
if (is_shutdown_.load()) {
throw GraphListenerShutdownError();
}
@@ -318,11 +332,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();
}
}
@@ -351,12 +365,6 @@ GraphListener::shutdown(const std::nothrow_t &) noexcept
}
}
bool
GraphListener::is_started()
{
return is_started_;
}
bool
GraphListener::is_shutdown()
{

View File

@@ -55,6 +55,34 @@ get_node_logger(const rcl_node_t * node)
return rclcpp::get_logger(logger_name);
}
// TODO(ahcorde): Remove deprecated class on the next release (in Rolling after Kilted).
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
rcpputils::fs::path
get_logging_directory()
{
char * log_dir = NULL;
auto allocator = rcutils_get_default_allocator();
rcl_logging_ret_t ret = rcl_logging_get_logging_directory(allocator, &log_dir);
if (RCL_LOGGING_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
std::string path{log_dir};
allocator.deallocate(log_dir, allocator.state);
return path;
}
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
std::filesystem::path
get_log_directory()
{

View File

@@ -275,6 +275,16 @@ 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

@@ -36,6 +36,9 @@ 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)
{}
@@ -47,7 +50,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.
node_base_->get_context()->get_graph_listener()->remove_node(this);
graph_listener_->remove_node(this);
}
}
@@ -416,7 +419,7 @@ NodeGraph::get_node_names_and_namespaces() const
rcl_get_error_string().str;
rcl_reset_error();
}
RCUTILS_LOG_ERROR_NAMED("rclcpp", "%s", error_msg.c_str());
// TODO(karsten1987): Append rcutils_error_message once it's in master
throw std::runtime_error(error_msg);
}
@@ -431,15 +434,20 @@ 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) {
error = std::string("could not destroy node names: ") + rcl_get_error_string().str;
// *INDENT-OFF*
// TODO(karsten1987): Append rcutils_error_message once it's in master
error = "could not destroy node names";
// *INDENT-ON*
}
rcl_ret_t ret_ns = rcutils_string_array_fini(&node_namespaces_c);
if (ret_ns != RCUTILS_RET_OK) {
error += std::string(", could not destroy node namespaces: ") + rcl_get_error_string().str;
// *INDENT-OFF*
// TODO(karsten1987): Append rcutils_error_message once it's in master
error += ", could not destroy node namespaces";
// *INDENT-ON*
}
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);
}
@@ -595,8 +603,8 @@ NodeGraph::get_graph_event()
}
// on first call, add node to graph_listener_
if (should_add_to_graph_listener_.exchange(false)) {
node_base_->get_context()->get_graph_listener()->add_node(this);
node_base_->get_context()->get_graph_listener()->start_if_not_started();
graph_listener_->add_node(this);
graph_listener_->start_if_not_started();
}
return event;
}

View File

@@ -192,65 +192,6 @@ 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(
@@ -260,39 +201,49 @@ __check_parameter_value_in_range(
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
if (!descriptor.integer_range.empty() && value.get_type() == rclcpp::PARAMETER_INTEGER) {
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;
}
int64_t v = value.get<int64_t>();
auto integer_range = descriptor.integer_range.at(0);
if (v == integer_range.from_value || v == integer_range.to_value) {
return result;
}
if ((v < integer_range.from_value) || (v > integer_range.to_value)) {
result.successful = false;
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) {
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;
}
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");
return result;
}
return result;
}

View File

@@ -47,9 +47,9 @@ ParameterService::ParameterService(
response->values.push_back(param.get_value_message());
}
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "Failed to get parameters: %s", ex.what());
RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Failed to get parameters: %s", ex.what());
} catch (const rclcpp::exceptions::ParameterUninitializedException & ex) {
RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "Failed to get parameters: %s", ex.what());
RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Failed to get parameters: %s", ex.what());
}
},
qos_profile, nullptr);
@@ -70,7 +70,7 @@ ParameterService::ParameterService(
return static_cast<rclcpp::ParameterType>(type);
});
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "Failed to get parameter types: %s", ex.what());
RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Failed to get parameter types: %s", ex.what());
}
},
qos_profile, nullptr);
@@ -91,7 +91,7 @@ ParameterService::ParameterService(
result = node_params->set_parameters_atomically(
{rclcpp::Parameter::from_parameter_msg(p)});
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "Failed to set parameter: %s", ex.what());
RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Failed to set parameter: %s", ex.what());
result.successful = false;
result.reason = ex.what();
}
@@ -119,7 +119,7 @@ ParameterService::ParameterService(
auto result = node_params->set_parameters_atomically(pvariants);
response->result = result;
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
RCLCPP_DEBUG(
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"), "Failed to set parameters atomically: %s", ex.what());
response->result.successful = false;
response->result.reason = "One or more parameters were not declared before setting";
@@ -139,7 +139,7 @@ ParameterService::ParameterService(
auto descriptors = node_params->describe_parameters(request->names);
response->descriptors = descriptors;
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "Failed to describe parameters: %s", ex.what());
RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Failed to describe parameters: %s", ex.what());
}
},
qos_profile, nullptr);

View File

@@ -67,13 +67,7 @@ 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)
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;
}
clock_->sleep_for(time_to_sleep);
return true;
}

View File

@@ -68,7 +68,6 @@ void
SignalHandler::signal_handler(
int signum, siginfo_t * siginfo, void * context)
{
RCLCPP_INFO(SignalHandler::get_logger(), "signal_handler(signum=%d)", signum);
auto & instance = SignalHandler::get_global_signal_handler();
auto old_signal_handler = instance.get_old_signal_handler(signum);
@@ -91,7 +90,6 @@ SignalHandler::signal_handler(
void
SignalHandler::signal_handler(int signum)
{
RCLCPP_INFO(SignalHandler::get_logger(), "signal_handler(signum=%d)", signum);
auto & instance = SignalHandler::get_global_signal_handler();
auto old_signal_handler = instance.get_old_signal_handler(signum);
if (
@@ -249,9 +247,6 @@ SignalHandler::signal_handler_common()
{
auto & instance = SignalHandler::get_global_signal_handler();
instance.signal_received_.store(true);
RCLCPP_DEBUG(
get_logger(),
"signal_handler(): notifying deferred signal handler");
instance.notify_signal_handler();
}
@@ -260,6 +255,7 @@ SignalHandler::deferred_signal_handler()
{
while (true) {
if (signal_received_.exchange(false)) {
RCLCPP_INFO(SignalHandler::get_logger(), "signal_handler(SIGINT/SIGTERM)");
RCLCPP_DEBUG(get_logger(), "deferred_signal_handler(): shutting down");
for (auto context_ptr : rclcpp::get_contexts()) {
if (context_ptr->get_init_options().shutdown_on_signal) {

View File

@@ -15,7 +15,6 @@
#include "rclcpp/typesupport_helpers.hpp"
#include <algorithm>
#include <functional>
#include <memory>
#include <sstream>
@@ -74,21 +73,6 @@ const void * get_typesupport_handle_impl(
}
}
// Trim leading and trailing whitespace from the string.
std::string string_trim(std::string_view str_v)
{
auto begin = std::find_if_not(str_v.begin(), str_v.end(), [](unsigned char ch) {
return std::isspace(ch);
});
auto end = std::find_if_not(str_v.rbegin(), str_v.rend(), [](unsigned char ch) {
return std::isspace(ch);
}).base();
if (begin >= end) {
return {};
}
return std::string(begin, end);
}
} // anonymous namespace
std::tuple<std::string, std::string, std::string>
@@ -98,7 +82,6 @@ extract_type_identifier(const std::string & full_type)
auto sep_position_back = full_type.find_last_of(type_separator);
auto sep_position_front = full_type.find_first_of(type_separator);
if (sep_position_back == std::string::npos ||
sep_position_front == 0 ||
sep_position_back == 0 ||
sep_position_back == full_type.length() - 1)
{
@@ -114,8 +97,7 @@ extract_type_identifier(const std::string & full_type)
}
std::string type_name = full_type.substr(sep_position_back + 1);
return std::make_tuple(
string_trim(package_name), string_trim(middle_module), string_trim(type_name));
return std::make_tuple(package_name, middle_module, type_name);
}
std::string get_typesupport_library_path(

View File

@@ -125,13 +125,11 @@ BENCHMARK_F(ServicePerformanceTest, async_send_response)(benchmark::State & stat
auto service = node->create_service<test_msgs::srv::Empty>(empty_service_name, callback);
reset_heap_counters();
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node->get_node_base_interface());
for (auto _ : state) {
(void)_;
state.PauseTiming();
// Clear executor queue
executor.spin_some();
rclcpp::spin_some(node->get_node_base_interface());
auto request = std::make_shared<test_msgs::srv::Empty::Request>();
auto future = empty_client->async_send_request(request);
@@ -139,7 +137,7 @@ BENCHMARK_F(ServicePerformanceTest, async_send_response)(benchmark::State & stat
benchmark::DoNotOptimize(service);
benchmark::ClobberMemory();
executor.spin_until_future_complete(future);
rclcpp::spin_until_future_complete(node->get_node_base_interface(), future);
}
if (callback_count == 0) {
state.SkipWithError("Service callback was not called");

View File

@@ -57,6 +57,11 @@ ament_add_test_label(test_client mimick)
if(TARGET test_client)
target_link_libraries(test_client ${PROJECT_NAME} mimick ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_clock test_clock.cpp)
ament_add_test_label(test_clock mimick)
if(TARGET test_clock)
target_link_libraries(test_clock ${PROJECT_NAME} mimick ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_clock_conditional test_clock_conditional.cpp)
ament_add_test_label(test_clock_conditional mimick)
if(TARGET test_clock_conditional)
@@ -529,6 +534,13 @@ if(TARGET test_executors_warmup)
target_link_libraries(test_executors_warmup ${PROJECT_NAME} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_static_single_threaded_executor executors/test_static_single_threaded_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
ament_add_test_label(test_static_single_threaded_executor mimick)
if(TARGET test_static_single_threaded_executor)
target_link_libraries(test_static_single_threaded_executor ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_multi_threaded_executor executors/test_multi_threaded_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_multi_threaded_executor)

View File

@@ -22,13 +22,40 @@
#include "rclcpp/experimental/executors/events_executor/events_executor.hpp"
#include "rclcpp/executors/single_threaded_executor.hpp"
#include "rclcpp/executors/static_single_threaded_executor.hpp"
#include "rclcpp/executors/multi_threaded_executor.hpp"
// suppress deprecated StaticSingleThreadedExecutor warning
// we define an alias that explicitly indicates that this class is deprecated, while avoiding
// polluting a lot of files the gcc pragmas
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
using DeprecatedStaticSingleThreadedExecutor = rclcpp::executors::StaticSingleThreadedExecutor;
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
using ExecutorTypes =
::testing::Types<
rclcpp::executors::SingleThreadedExecutor,
rclcpp::executors::MultiThreadedExecutor,
DeprecatedStaticSingleThreadedExecutor,
rclcpp::experimental::executors::EventsExecutor>;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
class ExecutorTypeNames
{
@@ -43,6 +70,16 @@ public:
if (std::is_same<T, rclcpp::executors::MultiThreadedExecutor>()) {
return "MultiThreadedExecutor";
}
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
if (std::is_same<T, DeprecatedStaticSingleThreadedExecutor>()) {
return "StaticSingleThreadedExecutor";
}
#ifdef __clang__
# pragma clang diagnostic pop
#endif
if (std::is_same<T, rclcpp::experimental::executors::EventsExecutor>()) {
return "EventsExecutor";
@@ -52,6 +89,8 @@ public:
}
};
// StaticSingleThreadedExecutor is not included in these tests for now, due to:
// https://github.com/ros2/rclcpp/issues/1219
using StandardExecutors =
::testing::Types<
rclcpp::executors::SingleThreadedExecutor,

View File

@@ -804,10 +804,8 @@ TEST(TestExecutors, testSpinUntilFutureCompleteNodePtr)
}
// Check spin functions with non default context
TYPED_TEST(TestExecutors, testSpinWithNonDefaultContext)
TEST(TestExecutors, testSpinWithNonDefaultContext)
{
using ExecutorType = TypeParam;
auto non_default_context = std::make_shared<rclcpp::Context>();
non_default_context->init(0, nullptr);
@@ -815,14 +813,9 @@ TYPED_TEST(TestExecutors, testSpinWithNonDefaultContext)
auto node =
std::make_unique<rclcpp::Node>("node", rclcpp::NodeOptions().context(non_default_context));
rclcpp::ExecutorOptions options;
options.context = non_default_context;
ExecutorType executor(options);
EXPECT_NO_THROW(executor.add_node(node->get_node_base_interface()));
EXPECT_NO_THROW(rclcpp::spin_some(node->get_node_base_interface()));
EXPECT_NO_THROW(executor.spin_some());
EXPECT_NO_THROW(executor.spin_all(1s));
EXPECT_NO_THROW(rclcpp::spin_all(node->get_node_base_interface(), 1s));
auto check_spin_until_future_complete = [&]() {
std::promise<bool> promise;
@@ -830,7 +823,8 @@ TYPED_TEST(TestExecutors, testSpinWithNonDefaultContext)
promise.set_value(true);
auto shared_future = future.share();
auto ret = executor.spin_until_future_complete(shared_future, 1s);
auto ret = rclcpp::spin_until_future_complete(
node->get_node_base_interface(), shared_future, 1s);
EXPECT_EQ(rclcpp::FutureReturnCode::SUCCESS, ret);
};
EXPECT_NO_THROW(check_spin_until_future_complete());

View File

@@ -285,11 +285,20 @@ public:
T executor;
};
#if !defined(_WIN32)
# ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
# endif
#endif
using MainExecutorTypes =
::testing::Types<
rclcpp::executors::SingleThreadedExecutor,
rclcpp::executors::MultiThreadedExecutor>;
rclcpp::executors::MultiThreadedExecutor,
DeprecatedStaticSingleThreadedExecutor>;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
// TODO(@fujitatomoya): this test excludes EventExecutor because it does not
// support simulation time used for this test to relax the racy condition.
// See more details for https://github.com/ros2/rclcpp/issues/2457.

View File

@@ -1,617 +0,0 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <chrono>
#include <memory>
#include <stdexcept>
#include "rclcpp/rclcpp.hpp"
#include "rcpputils/scope_exit.hpp"
#include "test_msgs/msg/empty.hpp"
#include "test_msgs/srv/empty.hpp"
#include "../../mocking_utils/patch.hpp"
#include "../../utils/rclcpp_gtest_macros.hpp"
namespace
{
struct NumberOfEntities
{
size_t subscriptions = 0;
size_t timers = 0;
size_t services = 0;
size_t clients = 0;
size_t waitables = 0;
};
std::unique_ptr<NumberOfEntities> get_number_of_default_entities(rclcpp::Node::SharedPtr node)
{
auto number_of_entities = std::make_unique<NumberOfEntities>();
node->for_each_callback_group(
[&number_of_entities](rclcpp::CallbackGroup::SharedPtr group)
{
if (!group->can_be_taken_from().load()) {
return;
}
group->find_subscription_ptrs_if(
[&number_of_entities](rclcpp::SubscriptionBase::SharedPtr &)
{
number_of_entities->subscriptions++; return false;
});
group->find_timer_ptrs_if(
[&number_of_entities](rclcpp::TimerBase::SharedPtr &)
{
number_of_entities->timers++; return false;
});
group->find_service_ptrs_if(
[&number_of_entities](rclcpp::ServiceBase::SharedPtr &)
{
number_of_entities->services++; return false;
});
group->find_client_ptrs_if(
[&number_of_entities](rclcpp::ClientBase::SharedPtr &)
{
number_of_entities->clients++; return false;
});
group->find_waitable_ptrs_if(
[&number_of_entities](rclcpp::Waitable::SharedPtr &)
{
number_of_entities->waitables++; return false;
});
});
return number_of_entities;
}
} // namespace
class TestStaticExecutorEntitiesCollector : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
entities_collector_ =
std::make_shared<rclcpp::executors::StaticExecutorEntitiesCollector>();
}
void TearDown()
{
rclcpp::shutdown();
}
rclcpp::executors::StaticExecutorEntitiesCollector::SharedPtr entities_collector_;
};
TEST_F(TestStaticExecutorEntitiesCollector, construct_destruct) {
EXPECT_EQ(0u, entities_collector_->get_number_of_subscriptions());
EXPECT_EQ(0u, entities_collector_->get_number_of_timers());
EXPECT_EQ(0u, entities_collector_->get_number_of_services());
EXPECT_EQ(0u, entities_collector_->get_number_of_clients());
EXPECT_EQ(0u, entities_collector_->get_number_of_waitables());
}
TEST_F(TestStaticExecutorEntitiesCollector, add_remove_node) {
auto node1 = std::make_shared<rclcpp::Node>("node1", "ns");
EXPECT_NO_THROW(entities_collector_->add_node(node1->get_node_base_interface()));
// Check adding second time
RCLCPP_EXPECT_THROW_EQ(
entities_collector_->add_node(node1->get_node_base_interface()),
std::runtime_error("Node has already been added to an executor."));
auto node2 = std::make_shared<rclcpp::Node>("node2", "ns");
EXPECT_FALSE(entities_collector_->remove_node(node2->get_node_base_interface()));
EXPECT_NO_THROW(entities_collector_->add_node(node2->get_node_base_interface()));
EXPECT_TRUE(entities_collector_->remove_node(node1->get_node_base_interface()));
EXPECT_FALSE(entities_collector_->remove_node(node1->get_node_base_interface()));
EXPECT_TRUE(entities_collector_->remove_node(node2->get_node_base_interface()));
auto node3 = std::make_shared<rclcpp::Node>("node3", "ns");
node3->get_node_base_interface()->get_associated_with_executor_atomic().exchange(true);
EXPECT_FALSE(entities_collector_->remove_node(node3->get_node_base_interface()));
}
TEST_F(TestStaticExecutorEntitiesCollector, init_bad_arguments) {
auto node = std::make_shared<rclcpp::Node>("node", "ns");
entities_collector_->add_node(node->get_node_base_interface());
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
rcl_allocator_t allocator = rcl_get_default_allocator();
auto shared_context = node->get_node_base_interface()->get_context();
rcl_context_t * context = shared_context->get_rcl_context().get();
EXPECT_EQ(
RCL_RET_OK,
rcl_wait_set_init(&wait_set, 100, 100, 100, 100, 100, 100, context, allocator));
RCPPUTILS_SCOPE_EXIT({EXPECT_EQ(RCL_RET_OK, rcl_wait_set_fini(&wait_set));});
rclcpp::GuardCondition guard_condition(shared_context);
// Check memory strategy is nullptr
rclcpp::memory_strategy::MemoryStrategy::SharedPtr memory_strategy = nullptr;
EXPECT_THROW(
entities_collector_->init(&wait_set, memory_strategy),
std::runtime_error);
}
TEST_F(TestStaticExecutorEntitiesCollector, add_remove_basic_node) {
auto node = std::make_shared<rclcpp::Node>("node", "ns");
const auto expected_number_of_entities = get_number_of_default_entities(node);
EXPECT_NE(nullptr, expected_number_of_entities);
entities_collector_->add_node(node->get_node_base_interface());
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
rcl_allocator_t allocator = rcl_get_default_allocator();
auto shared_context = node->get_node_base_interface()->get_context();
rcl_context_t * context = shared_context->get_rcl_context().get();
EXPECT_EQ(
RCL_RET_OK,
rcl_wait_set_init(&wait_set, 100, 100, 100, 100, 100, 100, context, allocator));
RCPPUTILS_SCOPE_EXIT({EXPECT_EQ(RCL_RET_OK, rcl_wait_set_fini(&wait_set));});
auto memory_strategy = rclcpp::memory_strategies::create_default_strategy();
rclcpp::GuardCondition guard_condition(shared_context);
entities_collector_->init(&wait_set, memory_strategy);
RCPPUTILS_SCOPE_EXIT(entities_collector_->fini());
EXPECT_EQ(
expected_number_of_entities->subscriptions,
entities_collector_->get_number_of_subscriptions());
EXPECT_EQ(expected_number_of_entities->timers, entities_collector_->get_number_of_timers());
EXPECT_EQ(expected_number_of_entities->services, entities_collector_->get_number_of_services());
EXPECT_EQ(expected_number_of_entities->clients, entities_collector_->get_number_of_clients());
// One extra for the executor
EXPECT_EQ(
1u + expected_number_of_entities->waitables,
entities_collector_->get_number_of_waitables());
EXPECT_TRUE(entities_collector_->remove_node(node->get_node_base_interface()));
entities_collector_->init(&wait_set, memory_strategy);
EXPECT_EQ(0u, entities_collector_->get_number_of_subscriptions());
EXPECT_EQ(0u, entities_collector_->get_number_of_timers());
EXPECT_EQ(0u, entities_collector_->get_number_of_services());
EXPECT_EQ(0u, entities_collector_->get_number_of_clients());
// Still one for the executor
EXPECT_EQ(1u, entities_collector_->get_number_of_waitables());
}
TEST_F(TestStaticExecutorEntitiesCollector, add_remove_node_out_of_scope) {
rclcpp::Context::SharedPtr shared_context = nullptr;
{
auto node1 = std::make_shared<rclcpp::Node>("node1", "ns");
auto node2 = std::make_shared<rclcpp::Node>("node2", "ns");
auto node3 = std::make_shared<rclcpp::Node>("node3", "ns");
entities_collector_->add_node(node1->get_node_base_interface());
entities_collector_->add_node(node2->get_node_base_interface());
entities_collector_->add_node(node3->get_node_base_interface());
shared_context = node1->get_node_base_interface()->get_context();
}
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
rcl_allocator_t allocator = rcl_get_default_allocator();
rcl_context_t * context = shared_context->get_rcl_context().get();
EXPECT_EQ(
RCL_RET_OK,
rcl_wait_set_init(&wait_set, 100, 100, 100, 100, 100, 100, context, allocator));
RCPPUTILS_SCOPE_EXIT({EXPECT_EQ(RCL_RET_OK, rcl_wait_set_fini(&wait_set));});
auto memory_strategy = rclcpp::memory_strategies::create_default_strategy();
rclcpp::GuardCondition guard_condition(shared_context);
// Expect weak_node pointers to be cleaned up and used
entities_collector_->init(&wait_set, memory_strategy);
RCPPUTILS_SCOPE_EXIT(entities_collector_->fini());
EXPECT_EQ(0u, entities_collector_->get_number_of_subscriptions());
EXPECT_EQ(0u, entities_collector_->get_number_of_timers());
EXPECT_EQ(0u, entities_collector_->get_number_of_services());
EXPECT_EQ(0u, entities_collector_->get_number_of_clients());
// Still one for the executor
EXPECT_EQ(1u, entities_collector_->get_number_of_waitables());
}
class TestWaitable : public rclcpp::Waitable
{
public:
void add_to_wait_set(rcl_wait_set_t &) override {}
bool is_ready(const rcl_wait_set_t &) override {return true;}
std::shared_ptr<void>
take_data() override
{
return nullptr;
}
void
execute(const std::shared_ptr<void> &) override {}
};
TEST_F(TestStaticExecutorEntitiesCollector, add_remove_node_with_entities) {
auto node = std::make_shared<rclcpp::Node>("node", "ns");
auto expected_number_of_entities = get_number_of_default_entities(node);
EXPECT_NE(nullptr, expected_number_of_entities);
// Create 1 of each entity type
auto subscription =
node->create_subscription<test_msgs::msg::Empty>(
"topic", rclcpp::QoS(10), [](test_msgs::msg::Empty::ConstSharedPtr) {});
auto timer =
node->create_wall_timer(std::chrono::seconds(60), []() {});
auto service =
node->create_service<test_msgs::srv::Empty>(
"service",
[](
const test_msgs::srv::Empty::Request::SharedPtr,
test_msgs::srv::Empty::Response::SharedPtr) {});
auto client = node->create_client<test_msgs::srv::Empty>("service");
auto waitable = std::make_shared<TestWaitable>();
// Adding a subscription could add another waitable, so we need to get the
// current number of waitables just before adding the new waitable.
expected_number_of_entities->waitables = get_number_of_default_entities(node)->waitables;
node->get_node_waitables_interface()->add_waitable(waitable, nullptr);
entities_collector_->add_node(node->get_node_base_interface());
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
rcl_allocator_t allocator = rcl_get_default_allocator();
auto shared_context = node->get_node_base_interface()->get_context();
rcl_context_t * context = shared_context->get_rcl_context().get();
EXPECT_EQ(
RCL_RET_OK,
rcl_wait_set_init(&wait_set, 100, 100, 100, 100, 100, 100, context, allocator));
RCPPUTILS_SCOPE_EXIT({EXPECT_EQ(RCL_RET_OK, rcl_wait_set_fini(&wait_set));});
auto memory_strategy = rclcpp::memory_strategies::create_default_strategy();
rclcpp::GuardCondition guard_condition(shared_context);
entities_collector_->init(&wait_set, memory_strategy);
RCPPUTILS_SCOPE_EXIT(entities_collector_->fini());
EXPECT_EQ(
1u + expected_number_of_entities->subscriptions,
entities_collector_->get_number_of_subscriptions());
EXPECT_EQ(1u + expected_number_of_entities->timers, entities_collector_->get_number_of_timers());
EXPECT_EQ(
1u + expected_number_of_entities->services,
entities_collector_->get_number_of_services());
EXPECT_EQ(
1u + expected_number_of_entities->clients,
entities_collector_->get_number_of_clients());
// One extra for the executor
EXPECT_EQ(
2u + expected_number_of_entities->waitables,
entities_collector_->get_number_of_waitables());
entities_collector_->remove_node(node->get_node_base_interface());
entities_collector_->init(&wait_set, memory_strategy);
EXPECT_EQ(0u, entities_collector_->get_number_of_subscriptions());
EXPECT_EQ(0u, entities_collector_->get_number_of_timers());
EXPECT_EQ(0u, entities_collector_->get_number_of_services());
EXPECT_EQ(0u, entities_collector_->get_number_of_clients());
// Still one for the executor
EXPECT_EQ(1u, entities_collector_->get_number_of_waitables());
}
TEST_F(TestStaticExecutorEntitiesCollector, add_callback_group) {
auto node = std::make_shared<rclcpp::Node>("node1", "ns");
rclcpp::CallbackGroup::SharedPtr cb_group = node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
entities_collector_->add_callback_group(cb_group, node->get_node_base_interface());
ASSERT_EQ(entities_collector_->get_all_callback_groups().size(), 1u);
}
TEST_F(TestStaticExecutorEntitiesCollector, add_callback_group_after_add_node) {
auto node = std::make_shared<rclcpp::Node>("node1", "ns");
rclcpp::CallbackGroup::SharedPtr cb_group = node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
entities_collector_->add_node(node->get_node_base_interface());
RCLCPP_EXPECT_THROW_EQ(
entities_collector_->add_callback_group(cb_group, node->get_node_base_interface()),
std::runtime_error("Callback group has already been added to an executor."));
}
TEST_F(TestStaticExecutorEntitiesCollector, add_callback_group_twice) {
auto node = std::make_shared<rclcpp::Node>("node1", "ns");
rclcpp::CallbackGroup::SharedPtr cb_group = node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
entities_collector_->add_callback_group(cb_group, node->get_node_base_interface());
ASSERT_EQ(entities_collector_->get_all_callback_groups().size(), 1u);
cb_group->get_associated_with_executor_atomic().exchange(false);
RCLCPP_EXPECT_THROW_EQ(
entities_collector_->add_callback_group(cb_group, node->get_node_base_interface()),
std::runtime_error("Callback group was already added to executor."));
}
TEST_F(TestStaticExecutorEntitiesCollector, prepare_wait_set_rcl_wait_set_clear_error) {
auto node = std::make_shared<rclcpp::Node>("node", "ns");
entities_collector_->add_node(node->get_node_base_interface());
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
rcl_allocator_t allocator = rcl_get_default_allocator();
auto shared_context = node->get_node_base_interface()->get_context();
rcl_context_t * context = shared_context->get_rcl_context().get();
EXPECT_EQ(
RCL_RET_OK,
rcl_wait_set_init(&wait_set, 100, 100, 100, 100, 100, 100, context, allocator));
RCPPUTILS_SCOPE_EXIT({EXPECT_EQ(RCL_RET_OK, rcl_wait_set_fini(&wait_set));});
auto memory_strategy = rclcpp::memory_strategies::create_default_strategy();
rclcpp::GuardCondition guard_condition(shared_context);
entities_collector_->init(&wait_set, memory_strategy);
RCPPUTILS_SCOPE_EXIT(entities_collector_->fini());
{
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_wait_set_clear, RCL_RET_ERROR);
std::shared_ptr<void> data = entities_collector_->take_data();
RCLCPP_EXPECT_THROW_EQ(
entities_collector_->execute(data),
std::runtime_error("Couldn't clear wait set"));
}
EXPECT_TRUE(entities_collector_->remove_node(node->get_node_base_interface()));
}
TEST_F(TestStaticExecutorEntitiesCollector, prepare_wait_set_rcl_wait_set_resize_error) {
auto node = std::make_shared<rclcpp::Node>("node", "ns");
entities_collector_->add_node(node->get_node_base_interface());
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
rcl_allocator_t allocator = rcl_get_default_allocator();
auto shared_context = node->get_node_base_interface()->get_context();
rcl_context_t * context = shared_context->get_rcl_context().get();
EXPECT_EQ(
RCL_RET_OK,
rcl_wait_set_init(&wait_set, 100, 100, 100, 100, 100, 100, context, allocator));
RCPPUTILS_SCOPE_EXIT({EXPECT_EQ(RCL_RET_OK, rcl_wait_set_fini(&wait_set));});
auto memory_strategy = rclcpp::memory_strategies::create_default_strategy();
rclcpp::GuardCondition guard_condition(shared_context);
entities_collector_->init(&wait_set, memory_strategy);
RCPPUTILS_SCOPE_EXIT(entities_collector_->fini());
{
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_wait_set_resize, RCL_RET_ERROR);
std::shared_ptr<void> data = entities_collector_->take_data();
RCLCPP_EXPECT_THROW_EQ(
entities_collector_->execute(data),
std::runtime_error("Couldn't resize the wait set: error not set"));
}
EXPECT_TRUE(entities_collector_->remove_node(node->get_node_base_interface()));
}
TEST_F(TestStaticExecutorEntitiesCollector, refresh_wait_set_not_initialized) {
RCLCPP_EXPECT_THROW_EQ(
entities_collector_->refresh_wait_set(std::chrono::nanoseconds(1000)),
std::runtime_error("Couldn't clear wait set"));
rcl_reset_error();
}
TEST_F(TestStaticExecutorEntitiesCollector, refresh_wait_set_rcl_wait_failed) {
auto node = std::make_shared<rclcpp::Node>("node", "ns");
entities_collector_->add_node(node->get_node_base_interface());
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
rcl_allocator_t allocator = rcl_get_default_allocator();
auto shared_context = node->get_node_base_interface()->get_context();
rcl_context_t * context = shared_context->get_rcl_context().get();
EXPECT_EQ(
RCL_RET_OK,
rcl_wait_set_init(&wait_set, 100, 100, 100, 100, 100, 100, context, allocator));
RCPPUTILS_SCOPE_EXIT({EXPECT_EQ(RCL_RET_OK, rcl_wait_set_fini(&wait_set));});
auto memory_strategy = rclcpp::memory_strategies::create_default_strategy();
rclcpp::GuardCondition guard_condition(shared_context);
entities_collector_->init(&wait_set, memory_strategy);
RCPPUTILS_SCOPE_EXIT(entities_collector_->fini());
{
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_wait, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
entities_collector_->refresh_wait_set(std::chrono::nanoseconds(1000)),
std::runtime_error("rcl_wait() failed: error not set"));
}
EXPECT_TRUE(entities_collector_->remove_node(node->get_node_base_interface()));
}
TEST_F(TestStaticExecutorEntitiesCollector, refresh_wait_set_add_handles_to_wait_set_failed) {
auto node = std::make_shared<rclcpp::Node>("node", "ns");
// Create 1 of each entity type
auto subscription =
node->create_subscription<test_msgs::msg::Empty>(
"topic", rclcpp::QoS(10), [](test_msgs::msg::Empty::ConstSharedPtr) {});
auto timer =
node->create_wall_timer(std::chrono::seconds(60), []() {});
auto service =
node->create_service<test_msgs::srv::Empty>(
"service",
[](
const test_msgs::srv::Empty::Request::SharedPtr,
test_msgs::srv::Empty::Response::SharedPtr) {});
auto client = node->create_client<test_msgs::srv::Empty>("service");
auto waitable = std::make_shared<TestWaitable>();
node->get_node_waitables_interface()->add_waitable(waitable, nullptr);
entities_collector_->add_node(node->get_node_base_interface());
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
rcl_allocator_t allocator = rcl_get_default_allocator();
auto shared_context = node->get_node_base_interface()->get_context();
rcl_context_t * context = shared_context->get_rcl_context().get();
EXPECT_EQ(
RCL_RET_OK,
rcl_wait_set_init(&wait_set, 100, 100, 100, 100, 100, 100, context, allocator));
RCPPUTILS_SCOPE_EXIT({EXPECT_EQ(RCL_RET_OK, rcl_wait_set_fini(&wait_set));});
auto memory_strategy = rclcpp::memory_strategies::create_default_strategy();
rclcpp::GuardCondition guard_condition(shared_context);
entities_collector_->init(&wait_set, memory_strategy);
RCPPUTILS_SCOPE_EXIT(entities_collector_->fini());
{
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_wait_set_add_subscription,
RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
entities_collector_->refresh_wait_set(std::chrono::nanoseconds(1000)),
std::runtime_error("Couldn't fill wait set"));
}
entities_collector_->remove_node(node->get_node_base_interface());
}
TEST_F(TestStaticExecutorEntitiesCollector, add_to_wait_set_nullptr) {
auto node = std::make_shared<rclcpp::Node>("node", "ns");
entities_collector_->add_node(node->get_node_base_interface());
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
rcl_allocator_t allocator = rcl_get_default_allocator();
auto shared_context = node->get_node_base_interface()->get_context();
rcl_context_t * context = shared_context->get_rcl_context().get();
EXPECT_EQ(
RCL_RET_OK,
rcl_wait_set_init(&wait_set, 100, 100, 100, 100, 100, 100, context, allocator));
RCPPUTILS_SCOPE_EXIT({EXPECT_EQ(RCL_RET_OK, rcl_wait_set_fini(&wait_set));});
auto memory_strategy = rclcpp::memory_strategies::create_default_strategy();
rclcpp::GuardCondition guard_condition(shared_context);
entities_collector_->init(&wait_set, memory_strategy);
RCPPUTILS_SCOPE_EXIT(entities_collector_->fini());
EXPECT_TRUE(entities_collector_->remove_node(node->get_node_base_interface()));
}
TEST_F(TestStaticExecutorEntitiesCollector, fill_memory_strategy_invalid_group) {
auto node = std::make_shared<rclcpp::Node>("node", "ns");
entities_collector_->add_node(node->get_node_base_interface());
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
rcl_allocator_t allocator = rcl_get_default_allocator();
auto shared_context = node->get_node_base_interface()->get_context();
rcl_context_t * context = shared_context->get_rcl_context().get();
EXPECT_EQ(
RCL_RET_OK,
rcl_wait_set_init(&wait_set, 100, 100, 100, 100, 100, 100, context, allocator));
RCPPUTILS_SCOPE_EXIT({EXPECT_EQ(RCL_RET_OK, rcl_wait_set_fini(&wait_set));});
auto memory_strategy = rclcpp::memory_strategies::create_default_strategy();
rclcpp::GuardCondition guard_condition(shared_context);
rclcpp::CallbackGroup::SharedPtr cb_group = node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
entities_collector_->add_callback_group(cb_group, node->get_node_base_interface());
ASSERT_EQ(entities_collector_->get_all_callback_groups().size(), 2u);
cb_group.reset();
entities_collector_->init(&wait_set, memory_strategy);
RCPPUTILS_SCOPE_EXIT(entities_collector_->fini());
ASSERT_EQ(entities_collector_->get_all_callback_groups().size(), 1u);
EXPECT_TRUE(entities_collector_->remove_node(node->get_node_base_interface()));
}
TEST_F(TestStaticExecutorEntitiesCollector, remove_callback_group_after_node) {
auto node = std::make_shared<rclcpp::Node>("node1", "ns");
rclcpp::CallbackGroup::SharedPtr cb_group = node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
entities_collector_->add_callback_group(cb_group, node->get_node_base_interface());
ASSERT_EQ(entities_collector_->get_all_callback_groups().size(), 1u);
node.reset();
RCLCPP_EXPECT_THROW_EQ(
entities_collector_->remove_callback_group(cb_group),
std::runtime_error("Node must not be deleted before its callback group(s)."));
}
TEST_F(TestStaticExecutorEntitiesCollector, remove_callback_group_twice) {
auto node = std::make_shared<rclcpp::Node>("node1", "ns");
rclcpp::CallbackGroup::SharedPtr cb_group = node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
entities_collector_->add_callback_group(cb_group, node->get_node_base_interface());
ASSERT_EQ(entities_collector_->get_all_callback_groups().size(), 1u);
entities_collector_->remove_callback_group(cb_group);
RCLCPP_EXPECT_THROW_EQ(
entities_collector_->remove_callback_group(cb_group),
std::runtime_error("Callback group needs to be associated with executor."));
}
TEST_F(TestStaticExecutorEntitiesCollector, remove_node_opposite_order) {
auto node1 = std::make_shared<rclcpp::Node>("node1", "ns");
EXPECT_NO_THROW(entities_collector_->add_node(node1->get_node_base_interface()));
auto node2 = std::make_shared<rclcpp::Node>("node2", "ns");
EXPECT_NO_THROW(entities_collector_->add_node(node2->get_node_base_interface()));
EXPECT_TRUE(entities_collector_->remove_node(node2->get_node_base_interface()));
}
TEST_F(
TestStaticExecutorEntitiesCollector,
add_callback_groups_from_nodes_associated_to_executor_add) {
auto node = std::make_shared<rclcpp::Node>("node", "ns");
rclcpp::CallbackGroup::SharedPtr cb_group = node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
entities_collector_->add_callback_group(cb_group, node->get_node_base_interface());
entities_collector_->add_node(node->get_node_base_interface());
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
rcl_allocator_t allocator = rcl_get_default_allocator();
auto shared_context = node->get_node_base_interface()->get_context();
rcl_context_t * context = shared_context->get_rcl_context().get();
EXPECT_EQ(
RCL_RET_OK,
rcl_wait_set_init(&wait_set, 100, 100, 100, 100, 100, 100, context, allocator));
RCPPUTILS_SCOPE_EXIT({EXPECT_EQ(RCL_RET_OK, rcl_wait_set_fini(&wait_set));});
auto memory_strategy = rclcpp::memory_strategies::create_default_strategy();
rclcpp::GuardCondition guard_condition(shared_context);
entities_collector_->init(&wait_set, memory_strategy);
RCPPUTILS_SCOPE_EXIT(entities_collector_->fini());
cb_group->get_associated_with_executor_atomic().exchange(false);
std::shared_ptr<void> data = entities_collector_->take_data();
entities_collector_->execute(data);
EXPECT_TRUE(entities_collector_->remove_node(node->get_node_base_interface()));
}

View File

@@ -0,0 +1,192 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <chrono>
#include <future>
#include <memory>
#include <stdexcept>
#include "rclcpp/exceptions.hpp"
#include "rclcpp/executors.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/rclcpp.hpp"
#include "test_msgs/srv/empty.hpp"
#include "./executor_types.hpp"
#include "../../mocking_utils/patch.hpp"
#include "../../utils/rclcpp_gtest_macros.hpp"
using namespace std::chrono_literals;
class TestStaticSingleThreadedExecutor : public ::testing::Test
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
}
void TearDown()
{
rclcpp::shutdown();
}
};
TEST_F(TestStaticSingleThreadedExecutor, add_callback_group_trigger_guard_failed) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
auto node = std::make_shared<rclcpp::Node>("node", "ns");
rclcpp::CallbackGroup::SharedPtr cb_group = node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
{
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
executor.add_callback_group(cb_group, node->get_node_base_interface(), true),
std::runtime_error("Failed to handle entities update on callback group add: error not set"));
}
}
TEST_F(TestStaticSingleThreadedExecutor, add_node_trigger_guard_failed) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
auto node = std::make_shared<rclcpp::Node>("node", "ns");
{
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
executor.add_node(node),
std::runtime_error("Failed to handle entities update on node add: error not set"));
}
}
TEST_F(TestStaticSingleThreadedExecutor, remove_callback_group_trigger_guard_failed) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
auto node = std::make_shared<rclcpp::Node>("node", "ns");
rclcpp::CallbackGroup::SharedPtr cb_group = node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
executor.add_callback_group(cb_group, node->get_node_base_interface(), true);
{
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
executor.remove_callback_group(cb_group, true),
std::runtime_error(
"Failed to handle entities update on callback group remove: error not set"));
}
}
TEST_F(TestStaticSingleThreadedExecutor, remove_node_failed) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
auto node = std::make_shared<rclcpp::Node>("node", "ns");
{
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
executor.remove_node(node, true),
std::runtime_error("Node '/ns/node' needs to be associated with an executor."));
}
}
TEST_F(TestStaticSingleThreadedExecutor, remove_node_trigger_guard_failed) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
auto node = std::make_shared<rclcpp::Node>("node", "ns");
executor.add_node(node);
{
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
executor.remove_node(node, true),
std::runtime_error("Failed to handle entities update on node remove: error not set"));
}
}
TEST_F(TestStaticSingleThreadedExecutor, execute_service) {
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
DeprecatedStaticSingleThreadedExecutor executor;
#ifdef __clang__
# pragma clang diagnostic pop
#endif
auto node = std::make_shared<rclcpp::Node>("node", "ns");
executor.add_node(node);
auto service =
node->create_service<test_msgs::srv::Empty>(
"service",
[](
const test_msgs::srv::Empty::Request::SharedPtr,
test_msgs::srv::Empty::Response::SharedPtr) {});
auto client = node->create_client<test_msgs::srv::Empty>("service");
std::promise<void> promise;
std::future<void> future = promise.get_future();
EXPECT_EQ(
rclcpp::FutureReturnCode::TIMEOUT,
executor.spin_until_future_complete(future, std::chrono::milliseconds(1)));
executor.remove_node(node);
executor.spin_until_future_complete(future, std::chrono::milliseconds(1));
}

View File

@@ -510,9 +510,7 @@ TEST_F(TestNodeGraph, get_node_names_and_namespaces_fini_errors)
"lib:rclcpp", rcutils_string_array_fini, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
node_graph()->get_node_names_and_namespaces(),
std::runtime_error(
"could not destroy node names: error not set, "
"could not destroy node namespaces: error not set"));
std::runtime_error("could not destroy node names, could not destroy node namespaces"));
}
TEST_F(TestNodeGraph, get_node_names_with_enclaves_fini_errors)

View File

@@ -192,7 +192,7 @@ TEST_F(TestNodeInterfaces, ni_init) {
/*
Testing macro'ed getters.
*/
TEST_F(TestNodeInterfaces, ni_all_init) {
TEST_F(TestNodeInterfaces, ni_all_init_non_const) {
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
using rclcpp::node_interfaces::NodeInterfaces;
@@ -252,3 +252,64 @@ TEST_F(TestNodeInterfaces, ni_all_init) {
time_source = ni.get_node_time_source_interface();
}
}
TEST_F(TestNodeInterfaces, ni_all_init_const) {
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
using rclcpp::node_interfaces::NodeInterfaces;
using rclcpp::node_interfaces::NodeBaseInterface;
using rclcpp::node_interfaces::NodeClockInterface;
using rclcpp::node_interfaces::NodeGraphInterface;
using rclcpp::node_interfaces::NodeLoggingInterface;
using rclcpp::node_interfaces::NodeTimersInterface;
using rclcpp::node_interfaces::NodeTopicsInterface;
using rclcpp::node_interfaces::NodeServicesInterface;
using rclcpp::node_interfaces::NodeWaitablesInterface;
using rclcpp::node_interfaces::NodeParametersInterface;
using rclcpp::node_interfaces::NodeTimeSourceInterface;
const auto ni = rclcpp::node_interfaces::NodeInterfaces<ALL_RCLCPP_NODE_INTERFACES>(*node);
{
auto base = ni.get<NodeBaseInterface>();
base = ni.get_node_base_interface();
EXPECT_STREQ(base->get_name(), "my_node"); // Test for functionality
}
{
auto clock = ni.get<NodeClockInterface>();
clock = ni.get_node_clock_interface();
clock->get_clock();
}
{
auto graph = ni.get<NodeGraphInterface>();
graph = ni.get_node_graph_interface();
}
{
auto logging = ni.get<NodeLoggingInterface>();
logging = ni.get_node_logging_interface();
}
{
auto timers = ni.get<NodeTimersInterface>();
timers = ni.get_node_timers_interface();
}
{
auto topics = ni.get<NodeTopicsInterface>();
topics = ni.get_node_topics_interface();
}
{
auto services = ni.get<NodeServicesInterface>();
services = ni.get_node_services_interface();
}
{
auto waitables = ni.get<NodeWaitablesInterface>();
waitables = ni.get_node_waitables_interface();
}
{
auto parameters = ni.get<NodeParametersInterface>();
parameters = ni.get_node_parameters_interface();
}
{
auto time_source = ni.get<NodeTimeSourceInterface>();
time_source = ni.get_node_time_source_interface();
}
}

View File

@@ -112,12 +112,10 @@ protected:
auto req_id = client->async_send_request(request, std::move(callback));
auto start = std::chrono::steady_clock::now();
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
while (!received_response &&
(std::chrono::steady_clock::now() - start) < timeout)
{
executor.spin_some();
rclcpp::spin_some(node);
}
if (!received_response) {
@@ -358,12 +356,10 @@ TYPED_TEST(TestAllClientTypesWithServer, on_new_response_callback)
this->template async_send_request<ClientType, test_msgs::srv::Empty::Request>(client, request);
auto start = std::chrono::steady_clock::now();
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(server_node);
while (server_requests_count == 0 &&
(std::chrono::steady_clock::now() - start) < std::chrono::seconds(10))
{
executor.spin_some();
rclcpp::spin_some(server_node);
}
ASSERT_EQ(server_requests_count, 1u);
@@ -384,7 +380,7 @@ TYPED_TEST(TestAllClientTypesWithServer, on_new_response_callback)
while (server_requests_count == 1 &&
(std::chrono::steady_clock::now() - start) < std::chrono::seconds(10))
{
executor.spin_some();
rclcpp::spin_some(server_node);
}
ASSERT_EQ(server_requests_count, 2u);
@@ -406,7 +402,7 @@ TYPED_TEST(TestAllClientTypesWithServer, on_new_response_callback)
while (server_requests_count < 5 &&
(std::chrono::steady_clock::now() - start) < std::chrono::seconds(10))
{
executor.spin_some();
rclcpp::spin_some(server_node);
}
ASSERT_EQ(server_requests_count, 5u);
@@ -496,12 +492,10 @@ void client_async_send_request_callback_with_request(
auto req_id = client->async_send_request(request, std::move(callback));
auto start = std::chrono::steady_clock::now();
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
while (!received_response &&
(std::chrono::steady_clock::now() - start) < std::chrono::seconds(1))
{
executor.spin_some();
rclcpp::spin_some(node);
}
EXPECT_TRUE(received_response);
EXPECT_FALSE(client->remove_pending_request(req_id));
@@ -559,29 +553,25 @@ void client_qos_depth(rclcpp::Node::SharedPtr node)
}
auto start = std::chrono::steady_clock::now();
rclcpp::executors::SingleThreadedExecutor server_executor;
server_executor.add_node(server_node);
while ((server_cb_count_ < client_requests) &&
(std::chrono::steady_clock::now() - start) < 2s)
{
server_executor.spin_some();
rclcpp::spin_some(server_node);
std::this_thread::sleep_for(2ms);
}
EXPECT_GT(server_cb_count_, client_qos_profile.depth());
start = std::chrono::steady_clock::now();
rclcpp::executors::SingleThreadedExecutor client_executor;
client_executor.add_node(node);
while ((client_cb_count_ < client_qos_profile.depth()) &&
(std::chrono::steady_clock::now() - start) < 1s)
{
client_executor.spin_some();
rclcpp::spin_some(node);
}
// Spin an extra time to check if client QoS depth has been ignored,
// so more client callbacks might be called than expected.
client_executor.spin_some();
rclcpp::spin_some(node);
EXPECT_EQ(client_cb_count_, client_qos_profile.depth());
}

View File

@@ -0,0 +1,238 @@
// Copyright 2024 Cellumation GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <chrono>
#include <rcpputils/compile_warnings.hpp>
#include "rcl/error_handling.h"
#include "rcl/time.h"
#include "rclcpp/clock.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/time_source.hpp"
#include "../utils/rclcpp_gtest_macros.hpp"
using namespace std::chrono_literals;
class TestClockWakeup : public ::testing::TestWithParam<rcl_clock_type_e>
{
public:
void test_wakeup_before_sleep(const rclcpp::Clock::SharedPtr & clock)
{
std::atomic_bool thread_finished = false;
std::thread wait_thread = std::thread(
[&clock, &thread_finished]()
{
// make sure the thread starts sleeping late
std::this_thread::sleep_for(std::chrono::milliseconds(100));
clock->sleep_until(clock->now() + std::chrono::seconds(3));
thread_finished = true;
});
RCPPUTILS_DEPRECATION_WARNING_OFF_START
// notify the clock, that the sleep shall be interrupted
clock->cancel_sleep_or_wait();
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
while (!thread_finished && start_time + std::chrono::seconds(1) > cur_time) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
cur_time = std::chrono::steady_clock::now();
}
wait_thread.join();
EXPECT_TRUE(thread_finished);
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
}
void test_wakeup_after_sleep(const rclcpp::Clock::SharedPtr & clock)
{
std::atomic_bool thread_finished = false;
std::thread wait_thread = std::thread(
[&clock, &thread_finished]()
{
clock->sleep_until(clock->now() + std::chrono::seconds(3));
thread_finished = true;
});
// make sure the thread is already sleeping before we send the cancel
std::this_thread::sleep_for(std::chrono::milliseconds(100));
RCPPUTILS_DEPRECATION_WARNING_OFF_START
// notify the clock, that the sleep shall be interrupted
clock->cancel_sleep_or_wait();
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
while (!thread_finished && start_time + std::chrono::seconds(1) > cur_time) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
cur_time = std::chrono::steady_clock::now();
}
wait_thread.join();
EXPECT_TRUE(thread_finished);
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
}
protected:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
void SetUp()
{
node = std::make_shared<rclcpp::Node>("my_node");
}
void TearDown()
{
node.reset();
}
rclcpp::Node::SharedPtr node;
};
INSTANTIATE_TEST_SUITE_P(
Clocks,
TestClockWakeup,
::testing::Values(
RCL_SYSTEM_TIME, RCL_ROS_TIME, RCL_STEADY_TIME
));
TEST_P(TestClockWakeup, wakeup_sleep) {
auto clock = std::make_shared<rclcpp::Clock>(GetParam());
test_wakeup_after_sleep(clock);
test_wakeup_before_sleep(clock);
}
TEST_F(TestClockWakeup, wakeup_sleep_ros_time_active) {
node->set_parameter({"use_sim_time", true});
auto clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
rclcpp::TimeSource time_source(node);
time_source.attachClock(clock);
EXPECT_TRUE(clock->ros_time_is_active());
test_wakeup_after_sleep(clock);
test_wakeup_before_sleep(clock);
}
TEST_F(TestClockWakeup, no_wakeup_on_sim_time) {
node->set_parameter({"use_sim_time", true});
auto clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
rclcpp::TimeSource time_source(node);
time_source.attachClock(clock);
EXPECT_TRUE(clock->ros_time_is_active());
std::atomic_bool thread_finished = false;
std::thread wait_thread = std::thread(
[&clock, &thread_finished]()
{
// make sure the thread starts sleeping late
clock->sleep_until(clock->now() + std::chrono::milliseconds(10));
thread_finished = true;
});
// make sure, that the sim time clock does not wakeup, as no clock is provided
std::this_thread::sleep_for(std::chrono::milliseconds(500));
EXPECT_FALSE(thread_finished);
RCPPUTILS_DEPRECATION_WARNING_OFF_START
// notify the clock, that the sleep shall be interrupted
clock->cancel_sleep_or_wait();
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
while (!thread_finished && start_time + std::chrono::seconds(1) > cur_time) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
cur_time = std::chrono::steady_clock::now();
}
wait_thread.join();
EXPECT_TRUE(thread_finished);
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
}
TEST_F(TestClockWakeup, multiple_threads_wait_on_one_clock) {
auto clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
std::vector<std::atomic_bool> thread_finished(10);
for (std::atomic_bool & finished : thread_finished) {
finished = false;
}
std::vector<std::thread> threads;
for (size_t nr = 0; nr < thread_finished.size(); nr++) {
threads.push_back(
std::thread(
[&clock, &thread_finished, nr]()
{
// make sure the thread starts sleeping late
clock->sleep_until(clock->now() + std::chrono::seconds(10));
thread_finished[nr] = true;
}));
}
// wait a bit so all threads can execute the sleep_until
std::this_thread::sleep_for(std::chrono::milliseconds(500));
for (const std::atomic_bool & finished : thread_finished) {
EXPECT_FALSE(finished);
}
rclcpp::shutdown();
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
bool threads_finished = false;
while (!threads_finished && start_time + std::chrono::seconds(1) > cur_time) {
threads_finished = true;
for (const std::atomic_bool & finished : thread_finished) {
if (!finished) {
threads_finished = false;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
cur_time = std::chrono::steady_clock::now();
}
for (const std::atomic_bool & finished : thread_finished) {
EXPECT_TRUE(finished);
}
for (auto & thread : threads) {
thread.join();
}
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
}

View File

@@ -42,9 +42,7 @@ TEST(TestCreateTimer, timer_executes)
timer->cancel();
});
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
executor.spin_some();
rclcpp::spin_some(node);
ASSERT_TRUE(got_callback);
rclcpp::shutdown();

View File

@@ -342,12 +342,12 @@ TEST_F(TestExecutor, spin_all_fail_wait_set_clear) {
subscription =
rclcpp::create_subscription<test_msgs::msg::Empty>(
node_topics, "test", rclcpp::QoS(10), std::move(callback));
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_wait_set_clear, RCL_RET_ERROR);
dummy.spin_all(std::chrono::milliseconds(1));
// second spin_all triggers rcl_wait_set_clear that should be called
// whenever a waitset gets rebuild and it was not changed in size.
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_wait_set_clear, RCL_RET_ERROR);
RCLCPP_EXPECT_THROW_EQ(
// the first spin might trigger the rebuild, but only the second triggers
// it for sure, therefore we spin two times
dummy.spin_all(std::chrono::milliseconds(1));
dummy.spin_all(std::chrono::milliseconds(1)),
std::runtime_error("Couldn't clear the wait set: error not set"));
}

View File

@@ -78,10 +78,8 @@ public:
counter++;
});
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node_);
while (counter < expected_recv_msg_count) {
executor.spin_some();
rclcpp::spin_some(node_);
}
return messages;
}
@@ -109,13 +107,11 @@ public:
{
using clock = std::chrono::system_clock;
auto start = clock::now();
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node_);
while (!condition()) {
if ((clock::now() - start) > timeout) {
return false;
}
executor.spin_some();
rclcpp::spin_some(node_);
}
return true;
}

View File

@@ -372,18 +372,16 @@ TEST_F(TestGenericService, generic_service_qos_depth) {
}
auto start = std::chrono::steady_clock::now();
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(server_node);
while ((server_cb_count_ < server_qos_profile.depth()) &&
(std::chrono::steady_clock::now() - start) < 1s)
{
executor.spin_some();
rclcpp::spin_some(server_node);
std::this_thread::sleep_for(1ms);
}
// Spin an extra time to check if server QoS depth has been ignored,
// so more server responses might be processed than expected.
executor.spin_some();
rclcpp::spin_some(server_node);
EXPECT_EQ(server_cb_count_, server_qos_profile.depth());
}

View File

@@ -43,7 +43,9 @@ public:
node_graph_ = node_->get_node_graph_interface();
ASSERT_NE(nullptr, node_graph_);
graph_listener_ = rclcpp::contexts::get_global_default_context()->get_graph_listener();
graph_listener_ =
std::make_shared<rclcpp::graph_listener::GraphListener>(
rclcpp::contexts::get_global_default_context());
}
void TearDown()

View File

@@ -21,7 +21,7 @@
#include "rclcpp/rclcpp.hpp"
/*
Constructor
Construtctor
*/
TEST(TestIntraProcessBuffer, constructor) {
using MessageT = char;

View File

@@ -535,7 +535,7 @@ TEST(TestIntraProcessManager, add_pub_sub) {
* - Remove the first subscription from ipm and add a new one.
* - Publishes a unique_ptr message with a subscription not requesting ownership.
* - The received message is expected to be the same, the first subscription do not receive it.
* - Publishes a shared_ptr message with a subscription not requesting ownership.
* - Publishes a unique_ptr message with a subscription not requesting ownership.
* - The received message is expected to be the same.
*/
TEST(TestIntraProcessManager, single_subscription) {
@@ -587,9 +587,9 @@ TEST(TestIntraProcessManager, single_subscription) {
* - One is expected to receive the published message, while the other will receive a copy.
* - Publishes a unique_ptr message with 2 subscriptions not requesting ownership.
* - Both received messages are expected to be the same as the published one.
* - Publishes a shared_ptr message with 2 subscriptions requesting ownership.
* - Publishes a unique_ptr message with 2 subscriptions requesting ownership.
* - Both received messages are expected to be a copy of the published one.
* - Publishes a shared_ptr message with 2 subscriptions not requesting ownership.
* - Publishes a unique_ptr message with 2 subscriptions not requesting ownership.
* - Both received messages are expected to be the same as the published one.
*/
TEST(TestIntraProcessManager, multiple_subscriptions_same_type) {
@@ -694,9 +694,9 @@ TEST(TestIntraProcessManager, multiple_subscriptions_same_type) {
* - The 2 subscriptions not requesting ownership are expected to both receive the same copy
* of the message, one of the subscription requesting ownership is expected to receive a
* different copy, while the last is expected to receive the published message.
* - Publishes a shared_ptr message with 1 subscription requesting ownership and 1 not.
* - The subscription requesting ownership is expected to receive a copy of the message, while
* the other is expected to receive the published message
* - Publishes a unique_ptr message with 1 subscription requesting ownership and 1 not.
* - The subscription requesting ownership is expected to receive the published message, while
* the other is expected to receive a copy of the message
*/
TEST(TestIntraProcessManager, multiple_subscriptions_different_type) {
using IntraProcessManagerT = rclcpp::experimental::IntraProcessManager;

View File

@@ -129,8 +129,6 @@ TEST_F(TestMemoryStrategy, get_subscription_by_handle) {
EXPECT_EQ(
nullptr,
memory_strategy()->get_subscription_by_handle(subscription_handle, weak_groups_to_nodes));
// Clear all handles to cleanup when node is destroyed
memory_strategy()->clear_handles();
} // Node goes out of scope
EXPECT_EQ(
nullptr,
@@ -183,8 +181,6 @@ TEST_F(TestMemoryStrategy, get_service_by_handle) {
EXPECT_EQ(
nullptr,
memory_strategy()->get_service_by_handle(service_handle, weak_groups_to_nodes));
// Clear all handles to cleanup when node is destroyed
memory_strategy()->clear_handles();
} // Node goes out of scope
EXPECT_EQ(
nullptr,
@@ -232,11 +228,6 @@ TEST_F(TestMemoryStrategy, get_client_by_handle) {
EXPECT_EQ(
nullptr,
memory_strategy()->get_client_by_handle(client_handle, weak_groups_to_nodes));
// Clear all handles to cleanup when node is destroyed
memory_strategy()->clear_handles();
// reset client handle before node destruction, otherwise it tries to access node
// via weak_ptr in its deleter
client_handle.reset();
} // Node goes out of scope
EXPECT_EQ(
nullptr,
@@ -285,8 +276,6 @@ TEST_F(TestMemoryStrategy, get_timer_by_handle) {
EXPECT_EQ(
nullptr,
memory_strategy()->get_timer_by_handle(timer_handle, weak_groups_to_nodes));
// Clear all handles to cleanup when node is destroyed
memory_strategy()->clear_handles();
} // Node goes out of scope
EXPECT_EQ(
nullptr,
@@ -386,8 +375,6 @@ TEST_F(TestMemoryStrategy, get_group_by_subscription) {
EXPECT_EQ(
callback_group,
memory_strategy()->get_group_by_subscription(subscription, weak_groups_to_nodes));
// Clear all handles to cleanup when node is destroyed
memory_strategy()->clear_handles();
} // Node goes out of scope
// NodeBase(SubscriptionBase->rcl_node_t->NodeBase) is still alive.
EXPECT_EQ(
@@ -433,8 +420,6 @@ TEST_F(TestMemoryStrategy, get_group_by_service) {
EXPECT_EQ(
nullptr,
memory_strategy()->get_group_by_service(service, weak_groups_to_nodes));
// Clear all handles to cleanup when node is destroyed
memory_strategy()->clear_handles();
} // Node goes out of scope
EXPECT_EQ(
nullptr,
@@ -474,8 +459,6 @@ TEST_F(TestMemoryStrategy, get_group_by_client) {
EXPECT_EQ(
nullptr,
memory_strategy()->get_group_by_client(client, weak_groups_to_nodes));
// Clear all handles to cleanup when node is destroyed
memory_strategy()->clear_handles();
} // Node goes out of scope
EXPECT_EQ(
nullptr,
@@ -515,8 +498,6 @@ TEST_F(TestMemoryStrategy, get_group_by_timer) {
EXPECT_EQ(
nullptr,
memory_strategy()->get_group_by_timer(timer, weak_groups_to_nodes));
// Clear all handles to cleanup when node is destroyed
memory_strategy()->clear_handles();
} // Node goes out of scope
EXPECT_EQ(
nullptr,
@@ -555,8 +536,6 @@ TEST_F(TestMemoryStrategy, get_group_by_waitable) {
EXPECT_EQ(
nullptr,
memory_strategy()->get_group_by_waitable(waitable, weak_groups_to_nodes));
// Clear all handles to cleanup when node is destroyed
memory_strategy()->clear_handles();
} // Node goes out of scope
EXPECT_EQ(
nullptr,

View File

@@ -1365,203 +1365,6 @@ TEST_F(TestNode, set_parameter_undeclared_parameters_not_allowed) {
node->declare_parameter(name, 42, descriptor),
rclcpp::exceptions::InvalidParameterValueException);
}
{
// setting an array parameter with integer range descriptor
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.integer_range.resize(1);
auto & integer_range = descriptor.integer_range.at(0);
integer_range.from_value = 10;
integer_range.to_value = 18;
integer_range.step = 2;
node->declare_parameter(name, std::vector<int64_t>{10, 12, 14, 16, 18}, descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
EXPECT_EQ(value.get_value<std::vector<int64_t>>(), std::vector<int64_t>({10, 12, 14, 16, 18}));
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({12, 14, 10}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({12, 14, 10}));
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({10, 10, 10}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({10, 10, 10}));
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({18}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({15}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({20}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({8}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({12, 8, 18}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18}));
}
{
// setting an array parameter with integer range descriptor, from_value > to_value
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.integer_range.resize(1);
auto & integer_range = descriptor.integer_range.at(0);
integer_range.from_value = 20;
integer_range.to_value = 18;
integer_range.step = 1;
node->declare_parameter(name, std::vector<int64_t>({18, 20}), descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
EXPECT_EQ(value.get_value<std::vector<int64_t>>(), std::vector<int64_t>({18, 20}));
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({20, 18}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({20, 18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({18, 19, 20}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({20, 18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({10}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({20, 18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({25}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({20, 18}));
}
{
// setting an array parameter with integer range descriptor, from_value = to_value
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.integer_range.resize(1);
auto & integer_range = descriptor.integer_range.at(0);
integer_range.from_value = 18;
integer_range.to_value = 18;
integer_range.step = 1;
node->declare_parameter(name, std::vector<int64_t>({18}), descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
EXPECT_EQ(value.get_value<std::vector<int64_t>>(), std::vector<int64_t>({18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({17}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({19}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18}));
}
{
// setting an array parameter with integer range descriptor,
// step > distance(from_value, to_value)
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.integer_range.resize(1);
auto & integer_range = descriptor.integer_range.at(0);
integer_range.from_value = 18;
integer_range.to_value = 25;
integer_range.step = 10;
node->declare_parameter(name, std::vector<int64_t>({18, 25}), descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
EXPECT_EQ(value.get_value<std::vector<int64_t>>(), std::vector<int64_t>({18, 25}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({17}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18, 25}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({19}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18, 25}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({28}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18, 25}));
}
{
// setting an array parameter with integer range descriptor, distance not multiple of the step.
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.integer_range.resize(1);
auto & integer_range = descriptor.integer_range.at(0);
integer_range.from_value = 18;
integer_range.to_value = 28;
integer_range.step = 7;
node->declare_parameter(name, std::vector<int64_t>({18, 25, 28}), descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
EXPECT_EQ(value.get_value<std::vector<int64_t>>(), std::vector<int64_t>({18, 25, 28}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({17}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18, 25, 28}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({19}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18, 25, 28}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({32}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18, 25, 28}));
}
{
// setting an array parameter with integer range descriptor, step=0
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.integer_range.resize(1);
auto & integer_range = descriptor.integer_range.at(0);
integer_range.from_value = 10;
integer_range.to_value = 18;
integer_range.step = 0;
node->declare_parameter(name, std::vector<int64_t>({10, 11, 12, 13, 14, 15, 16, 17, 18}),
descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
EXPECT_EQ(value.get_value<std::vector<int64_t>>(),
std::vector<int64_t>({10, 11, 12, 13, 14, 15, 16, 17, 18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({9}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({10, 11, 12, 13, 14, 15, 16, 17, 18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({19}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({10, 11, 12, 13, 14, 15, 16, 17, 18}));
}
{
// setting an array parameter with integer range descriptor and wrong default value will throw
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.integer_range.resize(1);
auto & integer_range = descriptor.integer_range.at(0);
integer_range.from_value = 10;
integer_range.to_value = 18;
integer_range.step = 2;
ASSERT_THROW(
node->declare_parameter(name, std::vector<int64_t>({10, 11, 12, 13, 14, 15, 16, 17, 18}),
descriptor),
rclcpp::exceptions::InvalidParameterValueException);
}
{
// setting a parameter with floating point range descriptor
auto name = "parameter"_unq;
@@ -1732,201 +1535,6 @@ TEST_F(TestNode, set_parameter_undeclared_parameters_not_allowed) {
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 9.999)).successful);
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
}
{
// setting an array parameter with floating point range descriptor
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.floating_point_range.resize(1);
auto & floating_point_range = descriptor.floating_point_range.at(0);
floating_point_range.from_value = 10.0;
floating_point_range.to_value = 11.0;
floating_point_range.step = 0.2;
node->declare_parameter(name, std::vector<double>({10.0, 10.4, 11.0, 10.8, 10.2, 10.6}),
descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
EXPECT_EQ(value.get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.4, 11.0, 10.8, 10.2, 10.6}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({10.3}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.4, 11.0, 10.8, 10.2, 10.6}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({12.0}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.4, 11.0, 10.8, 10.2, 10.6}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({9.4}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.4, 11.0, 10.8, 10.2, 10.6}));
}
{
// setting an array parameter with floating point range descriptor, negative step
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.floating_point_range.resize(1);
auto & floating_point_range = descriptor.floating_point_range.at(0);
floating_point_range.from_value = 10.0;
floating_point_range.to_value = 11.0;
floating_point_range.step = -0.2;
node->declare_parameter(name, std::vector<double>({10.0, 10.2, 10.4, 10.6, 10.8, 11.0}),
descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
EXPECT_EQ(value.get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.2, 10.4, 10.6, 10.8, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({10.3}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.2, 10.4, 10.6, 10.8, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({12.0}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.2, 10.4, 10.6, 10.8, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({9.4}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.2, 10.4, 10.6, 10.8, 11.0}));
}
{
// setting an array parameter with floating point range descriptor, from_value > to_value
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.floating_point_range.resize(1);
auto & floating_point_range = descriptor.floating_point_range.at(0);
floating_point_range.from_value = 11.0;
floating_point_range.to_value = 10.0;
floating_point_range.step = 0.2;
node->declare_parameter(name, std::vector<double>({10.0, 11.0}), descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
EXPECT_EQ(value.get_value<std::vector<double>>(), std::vector<double>({10.0, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({10.2}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({12.0}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({9.4}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 11.0}));
}
{
// setting an array parameter with floating point range descriptor, from_value = to_value
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.floating_point_range.resize(1);
auto & floating_point_range = descriptor.floating_point_range.at(0);
floating_point_range.from_value = 10.0;
floating_point_range.to_value = 10.0;
floating_point_range.step = 0.2;
node->declare_parameter(name, std::vector<double>({10.0}), descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
EXPECT_EQ(value.get_value<std::vector<double>>(), std::vector<double>({10.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({11.2}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({12.0}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({9.4}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0}));
}
{
// setting an array parameter with floating point range descriptor, step > distance
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.floating_point_range.resize(1);
auto & floating_point_range = descriptor.floating_point_range.at(0);
floating_point_range.from_value = 10.0;
floating_point_range.to_value = 11.0;
floating_point_range.step = 2.2;
node->declare_parameter(name, std::vector<double>({10.0, 11.0}), descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
EXPECT_EQ(value.get_value<std::vector<double>>(), std::vector<double>({10.0, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({12.2}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({7.8}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 11.0}));
}
{
// setting an array parameter with floating point range descriptor,
// distance not multiple of the step.
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.floating_point_range.resize(1);
auto & floating_point_range = descriptor.floating_point_range.at(0);
floating_point_range.from_value = 10.0;
floating_point_range.to_value = 11.0;
floating_point_range.step = 0.7;
node->declare_parameter(name, std::vector<double>({10.0, 10.7, 11.0}), descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
EXPECT_EQ(value.get_value<std::vector<double>>(), std::vector<double>({10.0, 10.7, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({12.2}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.7, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({11.4}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.7, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({9.3}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.7, 11.0}));
}
{
// setting an array parameter with floating point range descriptor, step=0
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.floating_point_range.resize(1);
auto & floating_point_range = descriptor.floating_point_range.at(0);
floating_point_range.from_value = 10.0;
floating_point_range.to_value = 11.0;
floating_point_range.step = 0.0;
node->declare_parameter(name, std::vector<double>({10.0, 10.0001, 10.5479051, 11.0}),
descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
EXPECT_EQ(value.get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.0001, 10.5479051, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({11.001}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.0001, 10.5479051, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({9.999}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.0001, 10.5479051, 11.0}));
}
{
// setting a parameter with a different type is still possible
// when having a descriptor specifying a type (type is a status, not a constraint).

View File

@@ -173,12 +173,3 @@ TEST_F(TestRate, incorrect_constuctor) {
rclcpp::Rate rate(rclcpp::Duration(-1, 0)),
std::invalid_argument("period must be greater than 0"));
}
TEST(TestRateBasic, invalid_context) {
rclcpp::init(0, nullptr);
rclcpp::Rate rate(1.0);
ASSERT_TRUE(rate.sleep());
rclcpp::shutdown();
EXPECT_NO_THROW(rate.sleep());
ASSERT_FALSE(rate.sleep());
}

View File

@@ -22,7 +22,7 @@
#include "rclcpp/experimental/buffers/ring_buffer_implementation.hpp"
/*
* Constructor
* Construtctor
*/
TEST(TestRingBufferImplementation, constructor) {
// Cannot create a buffer of size zero.
@@ -140,31 +140,6 @@ TEST(TestRingBufferImplementation, basic_usage_unique_ptr) {
EXPECT_EQ(false, rb.is_full());
}
TEST(TestRingBufferImplementation, test_buffer_clear) {
rclcpp::experimental::buffers::RingBufferImplementation<char> rb(2);
rb.enqueue('a');
rb.enqueue('b');
EXPECT_EQ(true, rb.has_data());
EXPECT_EQ(true, rb.is_full());
const auto all_data_vec = rb.get_all_data();
EXPECT_EQ(2u, all_data_vec.capacity());
EXPECT_EQ(2u, all_data_vec.size());
rb.clear();
EXPECT_EQ(false, rb.has_data());
EXPECT_EQ(false, rb.is_full());
const auto all_data_vec_empty = rb.get_all_data();
EXPECT_EQ(0u, all_data_vec_empty.capacity());
EXPECT_EQ(0u, all_data_vec_empty.size());
rb.enqueue('c');
rb.enqueue('d');
const auto c = rb.dequeue();
const auto d = rb.dequeue();
EXPECT_EQ('c', c);
EXPECT_EQ('d', d);
}
TEST(TestRingBufferImplementation, handle_nullptr_deletion) {
rclcpp::experimental::buffers::RingBufferImplementation<std::unique_ptr<int>> rb(3);
rb.enqueue(std::make_unique<int>(42));

View File

@@ -386,20 +386,17 @@ TEST_F(TestService, server_qos_depth) {
std::this_thread::sleep_for(10ms);
}
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(server_node);
auto start = std::chrono::steady_clock::now();
while ((server_cb_count_ < server_qos_profile.depth()) &&
(std::chrono::steady_clock::now() - start) < 1s)
{
executor.spin_some();
rclcpp::spin_some(server_node);
std::this_thread::sleep_for(1ms);
}
// Spin an extra time to check if server QoS depth has been ignored,
// so more server responses might be processed than expected.
executor.spin_some();
rclcpp::spin_some(server_node);
EXPECT_EQ(server_cb_count_, server_qos_profile.depth());
}

View File

@@ -87,9 +87,6 @@ protected:
TEST_F(TestServiceIntrospection, service_introspection_nominal)
{
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
auto request = std::make_shared<BasicTypes::Request>();
request->set__bool_value(true);
request->set__int64_value(42);
@@ -109,7 +106,7 @@ TEST_F(TestServiceIntrospection, service_introspection_nominal)
auto future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
executor.spin_until_future_complete(future, timeout));
rclcpp::spin_until_future_complete(node, future, timeout));
BasicTypes::Response::SharedPtr response = future.get();
ASSERT_EQ(response->bool_value, false);
@@ -118,7 +115,7 @@ TEST_F(TestServiceIntrospection, service_introspection_nominal)
// wrap up work to get all the service_event messages
auto start = std::chrono::steady_clock::now();
while (events.size() < 4 && (std::chrono::steady_clock::now() - start) < timeout) {
executor.spin_some();
rclcpp::spin_some(node);
}
std::map<uint8_t, std::shared_ptr<const BasicTypes::Event>> event_map;
@@ -177,9 +174,6 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_events)
service->configure_introspection(
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_OFF);
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
ASSERT_EQ(sub->get_publisher_count(), 0);
auto request = std::make_shared<BasicTypes::Request>();
@@ -188,10 +182,10 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_events)
auto future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
executor.spin_until_future_complete(future, timeout));
rclcpp::spin_until_future_complete(node, future, timeout));
auto start = std::chrono::steady_clock::now();
while ((std::chrono::steady_clock::now() - start) < timeout) {
executor.spin_some();
rclcpp::spin_some(node);
}
EXPECT_EQ(events.size(), 0U);
@@ -212,10 +206,10 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_events)
future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
executor.spin_until_future_complete(future, timeout));
rclcpp::spin_until_future_complete(node, future, timeout));
start = std::chrono::steady_clock::now();
while (events.size() < 2 && (std::chrono::steady_clock::now() - start) < timeout) {
executor.spin_some();
rclcpp::spin_some(node);
}
EXPECT_EQ(events.size(), 2U);
@@ -236,10 +230,10 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_events)
future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
executor.spin_until_future_complete(future, timeout));
rclcpp::spin_until_future_complete(node, future, timeout));
start = std::chrono::steady_clock::now();
while (events.size() < 2 && (std::chrono::steady_clock::now() - start) < timeout) {
executor.spin_some();
rclcpp::spin_some(node);
}
EXPECT_EQ(events.size(), 2U);
@@ -260,10 +254,10 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_events)
future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
executor.spin_until_future_complete(future, timeout));
rclcpp::spin_until_future_complete(node, future, timeout));
start = std::chrono::steady_clock::now();
while (events.size() < 4 && (std::chrono::steady_clock::now() - start) < timeout) {
executor.spin_some();
rclcpp::spin_some(node);
}
EXPECT_EQ(events.size(), 4U);
}
@@ -275,9 +269,6 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_event_cont
service->configure_introspection(
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
// Wait for the introspection to attach to our subscription
size_t tries = 1000;
while (this->sub->get_publisher_count() < 2 && tries-- > 0) {
@@ -291,10 +282,10 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_event_cont
auto future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
executor.spin_until_future_complete(future, timeout));
rclcpp::spin_until_future_complete(node, future, timeout));
auto start = std::chrono::steady_clock::now();
while (events.size() < 4 && (std::chrono::steady_clock::now() - start) < timeout) {
executor.spin_some();
rclcpp::spin_some(node);
}
EXPECT_EQ(events.size(), 4U);
for (const auto & event : events) {
@@ -319,10 +310,10 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_event_cont
future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
executor.spin_until_future_complete(future, timeout));
rclcpp::spin_until_future_complete(node, future, timeout));
start = std::chrono::steady_clock::now();
while (events.size() < 4 && (std::chrono::steady_clock::now() - start) < timeout) {
executor.spin_some();
rclcpp::spin_some(node);
}
EXPECT_EQ(events.size(), 4U);
for (const auto & event : events) {
@@ -359,10 +350,10 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_event_cont
future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
executor.spin_until_future_complete(future, timeout));
rclcpp::spin_until_future_complete(node, future, timeout));
start = std::chrono::steady_clock::now();
while (events.size() < 4 && (std::chrono::steady_clock::now() - start) < timeout) {
executor.spin_some();
rclcpp::spin_some(node);
}
EXPECT_EQ(events.size(), 4U);
for (const auto & event : events) {
@@ -399,10 +390,10 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_event_cont
future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
executor.spin_until_future_complete(future, timeout));
rclcpp::spin_until_future_complete(node, future, timeout));
start = std::chrono::steady_clock::now();
while (events.size() < 4 && (std::chrono::steady_clock::now() - start) < timeout) {
executor.spin_some();
rclcpp::spin_some(node);
}
EXPECT_EQ(events.size(), 4U);
for (const auto & event : events) {

View File

@@ -69,13 +69,11 @@ public:
{
using clock = std::chrono::system_clock;
auto start = clock::now();
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
while (!condition()) {
if ((clock::now() - start) > timeout) {
return false;
}
executor.spin_some();
rclcpp::spin_some(node);
}
return true;
}

View File

@@ -158,15 +158,3 @@ TEST(TypesupportHelpersTest, test_throw_exception_with_invalid_type) {
rclcpp::get_action_typesupport_handle(invalid_type, "rosidl_typesupport_cpp", *library),
std::runtime_error);
}
TEST(TypesupportHelpersTest, throws_exception_if_filetype_has_multiple_slashes_at_start) {
EXPECT_ANY_THROW(rclcpp::extract_type_identifier("//name_with_slashes_at_start"));
}
TEST(TypesupportHelpersTestV3, ProcessesValidTypeWithWhitespace) {
std::string package, middle, name;
std::tie(package, middle, name) = rclcpp::extract_type_identifier(" package/ name ");
EXPECT_EQ(package, "package");
EXPECT_TRUE(middle.empty());
EXPECT_EQ(name, "name");
}

View File

@@ -134,3 +134,32 @@ TEST(TestUtilities, wait_for_last_message) {
rclcpp::shutdown();
}
TEST(TestUtilities, wait_for_message_custom_context) {
auto context = std::make_shared<rclcpp::Context>();
context->init(0, nullptr);
auto node_opt = rclcpp::NodeOptions().context(context);
auto node = std::make_shared<rclcpp::Node>("wait_for_message_custom_context_node", node_opt);
using MsgT = test_msgs::msg::Strings;
auto pub = node->create_publisher<MsgT>("wait_for_message_topic", 10);
MsgT out;
auto received = false;
auto wait = std::async(
[&]() {
auto ret = rclcpp::wait_for_message(out, node, "wait_for_message_topic", 5s);
EXPECT_TRUE(ret);
received = true;
});
for (auto i = 0u; i < 10 && received == false; ++i) {
pub->publish(*get_messages_strings()[0]);
std::this_thread::sleep_for(1s);
}
ASSERT_TRUE(received);
EXPECT_EQ(out, *get_messages_strings()[0]);
context->shutdown("test complete");
}

View File

@@ -3,33 +3,37 @@ Changelog for package rclcpp_action
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30.1.2 (2025-10-21)
29.5.7 (2026-02-09)
-------------------
* it misses the iterator second to lock the weakptr. (`#2958 <https://github.com/ros2/rclcpp/issues/2958>`_)
* try aborting before canceling 1st on dtor of ServerGoalHandle. (`#2953 <https://github.com/ros2/rclcpp/issues/2953>`_)
* Contributors: Tomoya Fujita
* Update exception documentation for goal cancellation in ServerGoalHandle (`#3019 <https://github.com/ros2/rclcpp/issues/3019>`_) (`#3022 <https://github.com/ros2/rclcpp/issues/3022>`_)
* Contributors: mergify[bot]
30.1.1 (2025-09-11)
-------------------
* deprecate rclcpp::spin_some and rclcpp::spin_all (`#2848 <https://github.com/ros2/rclcpp/issues/2848>`_)
* Contributors: Alberto Soragna
30.1.0 (2025-07-29)
-------------------
* fix cmake deprecation (`#2914 <https://github.com/ros2/rclcpp/issues/2914>`_)
* Contributors: mosfet80
30.0.0 (2025-07-01)
29.5.6 (2025-12-23)
-------------------
29.6.1 (2025-06-23)
29.5.5 (2025-11-18)
-------------------
* Replace std::default_random_engine with std::mt19937 (rolling) (`#2843 <https://github.com/ros2/rclcpp/issues/2843>`_)
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_)
* Contributors: Alejandro Hernández Cordero, keeponoiro
* Fix REP url locations (`#2987 <https://github.com/ros2/rclcpp/issues/2987>`_) (`#2989 <https://github.com/ros2/rclcpp/issues/2989>`_)
* Contributors: mergify[bot]
29.6.0 (2025-04-25)
29.5.4 (2025-10-21)
-------------------
* it misses the iterator second to lock the weakptr. (`#2958 <https://github.com/ros2/rclcpp/issues/2958>`_) (`#2959 <https://github.com/ros2/rclcpp/issues/2959>`_)
* Contributors: mergify[bot]
29.5.3 (2025-09-11)
-------------------
* fix cmake deprecation (`#2914 <https://github.com/ros2/rclcpp/issues/2914>`_) (`#2915 <https://github.com/ros2/rclcpp/issues/2915>`_)
* Contributors: mergify[bot]
29.5.2 (2025-07-07)
-------------------
29.5.1 (2025-06-23)
-------------------
* Replace std::default_random_engine with std::mt19937 (rolling) (`#2843 <https://github.com/ros2/rclcpp/issues/2843>`_) (`#2866 <https://github.com/ros2/rclcpp/issues/2866>`_)
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_) (`#2855 <https://github.com/ros2/rclcpp/issues/2855>`_)
* Contributors: mergify[bot]
29.5.0 (2025-04-18)
-------------------

View File

@@ -1,10 +1,10 @@
This document is a declaration of software quality for the `rclcpp_action` 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_action` package, based on the guidelines in [REP-2004](https://reps.openrobotics.org/rep-2004/).
# rclcpp_action Quality Declaration
The package `rclcpp_action` 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]
@@ -53,7 +53,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:
@@ -179,7 +179,7 @@ It is **Quality Level 1**, see its [Quality Declaration document](https://github
## Platform Support [6]
`rclcpp_action` 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_action` 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_action/)
@@ -191,4 +191,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

@@ -24,8 +24,6 @@
#include "action_msgs/msg/goal_status.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp_action/visibility_control.hpp"
#include "rclcpp_action/types.hpp"
@@ -105,19 +103,11 @@ protected:
_execute();
/// Transition the goal to canceled state if it never reached a terminal state.
/// Returns true if transitioned to canceled, else false.
/// \internal
RCLCPP_ACTION_PUBLIC
bool
try_canceling() noexcept;
/// Transition the goal to aborted state if it never reached a terminal state.
/// Returns true if transitioned to aborted, else false.
/// \internal
RCLCPP_ACTION_PUBLIC
bool
try_aborting() noexcept;
// End API for communication between ServerGoalHandleBase and ServerGoalHandle<>
// -----------------------------------------------------------------------------
@@ -210,7 +200,7 @@ public:
* This is a terminal state, no more methods should be called on a goal handle after this is
* called.
*
* \throws rclcpp::exceptions::RCLError If the goal is in any state besides executing.
* \throws rclcpp::exceptions::RCLError If a cancel request for this goal has not been received.
*
* \param[in] result_msg the final result to send to clients.
*/
@@ -253,22 +243,11 @@ public:
virtual ~ServerGoalHandle()
{
try {
// Abort goal if handle was allowed to destruct without reaching a terminal state
if (try_aborting()) {
auto null_result = std::make_shared<typename ActionT::Impl::GetResultService::Response>();
null_result->status = action_msgs::msg::GoalStatus::STATUS_ABORTED;
on_terminal_state_(uuid_, null_result);
} else if (try_canceling()) {
// Cancel goal if handle was allowed to destruct without reaching a terminal state
auto null_result = std::make_shared<typename ActionT::Impl::GetResultService::Response>();
null_result->status = action_msgs::msg::GoalStatus::STATUS_CANCELED;
on_terminal_state_(uuid_, null_result);
}
} catch (const std::exception & ex) {
RCLCPP_DEBUG(
rclcpp::get_logger("rclcpp_action"),
"Failed to abort/cancel goal handler in destructor: %s", ex.what());
// Cancel goal if handle was allowed to destruct without reaching a terminal state
if (try_canceling()) {
auto null_result = std::make_shared<typename ActionT::Impl::GetResultService::Response>();
null_result->status = action_msgs::msg::GoalStatus::STATUS_CANCELED;
on_terminal_state_(uuid_, null_result);
}
}

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_action</name>
<version>30.1.2</version>
<version>29.5.7</version>
<description>Adds action APIs for C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -13,7 +13,6 @@
// limitations under the License.
#include <memory>
#include <mutex>
#include "rcl_action/action_server.h"
#include "rcl_action/goal_handle.h"
@@ -136,24 +135,6 @@ ServerGoalHandleBase::try_canceling() noexcept
return RCL_RET_OK == ret;
}
return is_cancelable;
}
bool
ServerGoalHandleBase::try_aborting() noexcept
{
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
rcl_ret_t ret;
// Check if the goal is abortable
const bool is_abortable = rcl_action_goal_handle_is_abortable(rcl_handle_.get());
if (is_abortable) {
// Transition to ABORTED
ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_ABORT);
if (RCL_RET_OK != ret) {
return false;
}
}
return is_abortable;
return false;
}
} // namespace rclcpp_action

View File

@@ -518,11 +518,9 @@ TEST_F(TestServer, publish_status_accepted)
// 10 seconds
const size_t max_tries = 10 * 1000 / 100;
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
for (size_t retry = 0; retry < max_tries && received_msgs.size() != 1u; ++retry) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
executor.spin_some();
rclcpp::spin_some(node);
}
ASSERT_LT(0u, received_msgs.size());
@@ -584,11 +582,9 @@ TEST_F(TestServer, publish_status_canceling)
// 10 seconds
const size_t max_tries = 10 * 1000 / 100;
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
for (size_t retry = 0; retry < max_tries && received_msgs.size() < 2u; ++retry) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
executor.spin_some();
rclcpp::spin_some(node);
}
ASSERT_LT(0u, received_msgs.size());
@@ -644,12 +640,10 @@ TEST_F(TestServer, publish_status_canceled)
received_handle->canceled(std::make_shared<Fibonacci::Result>());
// 10 seconds
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
const size_t max_tries = 10 * 1000 / 100;
for (size_t retry = 0; retry < max_tries && received_msgs.size() < 3u; ++retry) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
executor.spin_some();
rclcpp::spin_some(node);
}
ASSERT_LT(0u, received_msgs.size());
@@ -703,12 +697,10 @@ TEST_F(TestServer, publish_status_succeeded)
received_handle->succeed(std::make_shared<Fibonacci::Result>());
// 10 seconds
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
const size_t max_tries = 10 * 1000 / 100;
for (size_t retry = 0; retry < max_tries && received_msgs.size() < 2u; ++retry) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
executor.spin_some();
rclcpp::spin_some(node);
}
ASSERT_LT(0u, received_msgs.size());
@@ -762,12 +754,10 @@ TEST_F(TestServer, publish_status_aborted)
received_handle->abort(std::make_shared<Fibonacci::Result>());
// 10 seconds
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
const size_t max_tries = 10 * 1000 / 100;
for (size_t retry = 0; retry < max_tries && received_msgs.size() < 2u; ++retry) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
executor.spin_some();
rclcpp::spin_some(node);
}
ASSERT_LT(0u, received_msgs.size());
@@ -824,12 +814,10 @@ TEST_F(TestServer, publish_feedback)
received_handle->publish_feedback(sent_message);
// 10 seconds
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
const size_t max_tries = 10 * 1000 / 100;
for (size_t retry = 0; retry < max_tries && received_msgs.size() < 1u; ++retry) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
executor.spin_some();
rclcpp::spin_some(node);
}
ASSERT_EQ(1u, received_msgs.size());
@@ -890,13 +878,10 @@ TEST_F(TestServer, get_result)
result->sequence = {5, 8, 13, 21};
received_handle->succeed(result);
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
// Wait for the result request to be received
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
executor.spin_until_future_complete(future));
rclcpp::spin_until_future_complete(node, future));
auto response = future.get();
EXPECT_EQ(action_msgs::msg::GoalStatus::STATUS_SUCCEEDED, response->status);
@@ -906,13 +891,13 @@ TEST_F(TestServer, get_result)
rclcpp::sleep_for(2 * result_timeout);
// Allow for expiration to take place
executor.spin_some();
rclcpp::spin_some(node);
// Send and wait for another result request
future = result_client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
executor.spin_until_future_complete(future));
rclcpp::spin_until_future_complete(node, future));
response = future.get();
EXPECT_EQ(action_msgs::msg::GoalStatus::STATUS_UNKNOWN, response->status);
@@ -961,12 +946,9 @@ TEST_F(TestServer, get_result_deferred)
request->goal_id.uuid = uuid;
auto future = result_client->async_send_request(request);
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
// Process request first
rclcpp::sleep_for(std::chrono::milliseconds(10)); // Give a chance for the request to be served
executor.spin_some();
rclcpp::spin_some(node);
// Send a result
auto result = std::make_shared<Fibonacci::Result>();
@@ -976,7 +958,7 @@ TEST_F(TestServer, get_result_deferred)
// Wait for the result request to be received
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
executor.spin_until_future_complete(future));
rclcpp::spin_until_future_complete(node, future));
auto response = future.get();
EXPECT_EQ(action_msgs::msg::GoalStatus::STATUS_SUCCEEDED, response->status);
@@ -1060,13 +1042,10 @@ public:
result->sequence = {5, 8, 13, 21};
goal_handle_->succeed(result);
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node_);
// Wait for the result request to be received
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
executor.spin_until_future_complete(future));
rclcpp::spin_until_future_complete(node_, future));
auto response = future.get();
EXPECT_EQ(action_msgs::msg::GoalStatus::STATUS_SUCCEEDED, response->status);
@@ -1076,13 +1055,13 @@ public:
rclcpp::sleep_for(std::chrono::milliseconds(100));
// Allow for expiration to take place
executor.spin_some();
rclcpp::spin_some(node_);
// Send and wait for another result request
future = result_client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
executor.spin_until_future_complete(future));
rclcpp::spin_until_future_complete(node_, future));
}
protected:

View File

@@ -44,8 +44,6 @@ public:
bool try_cancel() {return try_canceling();}
bool try_abort() {return try_aborting();}
void cancel_goal() {_cancel_goal();}
};
@@ -134,20 +132,6 @@ TEST_F(TestServerGoalHandle, abort) {
EXPECT_THROW(handle_->abort(result), rclcpp::exceptions::RCLError);
}
TEST_F(TestServerGoalHandle, try_abort) {
handle_->execute();
test_msgs::action::Fibonacci::Result::SharedPtr result =
std::make_shared<test_msgs::action::Fibonacci::Result>();
EXPECT_TRUE(handle_->try_abort());
EXPECT_FALSE(handle_->is_canceling());
EXPECT_FALSE(handle_->is_active());
EXPECT_FALSE(handle_->is_executing());
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp_action", rcl_action_update_goal_state, RCL_RET_ERROR);
EXPECT_THROW(handle_->abort(result), rclcpp::exceptions::RCLError);
}
TEST_F(TestServerGoalHandle, succeed) {
handle_->execute();
test_msgs::action::Fibonacci::Result::SharedPtr result =

View File

@@ -2,34 +2,33 @@
Changelog for package rclcpp_components
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30.1.2 (2025-10-21)
29.5.7 (2026-02-09)
-------------------
30.1.1 (2025-09-11)
29.5.6 (2025-12-23)
-------------------
* Cleanup the dependencies in rclcpp_components. (`#2918 <https://github.com/ros2/rclcpp/issues/2918>`_)
* Contributors: Chris Lalancette
30.1.0 (2025-07-29)
29.5.5 (2025-11-18)
-------------------
* fix cmake deprecation (`#2914 <https://github.com/ros2/rclcpp/issues/2914>`_)
* Contributors: mosfet80
* Fix REP url locations (`#2987 <https://github.com/ros2/rclcpp/issues/2987>`_) (`#2989 <https://github.com/ros2/rclcpp/issues/2989>`_)
* Contributors: mergify[bot]
30.0.0 (2025-07-01)
29.5.4 (2025-10-21)
-------------------
* NEW PR: Add component_container for EventsExecutor (`#2885 <https://github.com/ros2/rclcpp/issues/2885>`_)
* make sure that plugin arg includes the double colon. (`#2878 <https://github.com/ros2/rclcpp/issues/2878>`_)
* Contributors: Mihir Rao, Tomoya Fujita
29.6.1 (2025-06-23)
29.5.3 (2025-09-11)
-------------------
* set thread names by node in component container isolated (`#2871 <https://github.com/ros2/rclcpp/issues/2871>`_)
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_)
* Contributors: Adam Aposhian, Alejandro Hernández Cordero
* fix cmake deprecation (`#2914 <https://github.com/ros2/rclcpp/issues/2914>`_) (`#2915 <https://github.com/ros2/rclcpp/issues/2915>`_)
* Contributors: mergify[bot]
29.6.0 (2025-04-25)
29.5.2 (2025-07-07)
-------------------
29.5.1 (2025-06-23)
-------------------
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_) (`#2855 <https://github.com/ros2/rclcpp/issues/2855>`_)
* Contributors: mergify[bot]
29.5.0 (2025-04-18)
-------------------

View File

@@ -19,9 +19,7 @@ find_package(ament_index_cpp REQUIRED)
find_package(class_loader REQUIRED)
find_package(composition_interfaces REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rcl_interfaces REQUIRED)
find_package(rcpputils REQUIRED)
find_package(rmw REQUIRED)
# Add an interface library that can be depended upon by libraries who register components
add_library(component INTERFACE)
@@ -41,15 +39,13 @@ target_include_directories(component_manager PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>")
target_link_libraries(component_manager PUBLIC
class_loader::class_loader
${composition_interfaces_TARGETS}
rclcpp::rclcpp
rmw::rmw
)
target_link_libraries(component_manager PRIVATE
ament_index_cpp::ament_index_cpp
class_loader::class_loader
rcpputils::rcpputils
${rcl_interfaces_TARGETS}
)
target_compile_definitions(component_manager
PRIVATE "RCLCPP_COMPONENTS_BUILDING_LIBRARY")
@@ -58,13 +54,7 @@ add_executable(
component_container
src/component_container.cpp
)
target_link_libraries(component_container PRIVATE component_manager rclcpp::rclcpp)
add_executable(
component_container_event
src/component_container_event.cpp
)
target_link_libraries(component_container_event PRIVATE component_manager rclcpp::rclcpp)
target_link_libraries(component_container component_manager rclcpp::rclcpp)
set(node_main_template_install_dir "share/${PROJECT_NAME}")
install(FILES
@@ -75,13 +65,19 @@ add_executable(
component_container_mt
src/component_container_mt.cpp
)
target_link_libraries(component_container_mt PRIVATE component_manager rclcpp::rclcpp)
target_link_libraries(component_container_mt component_manager rclcpp::rclcpp)
add_executable(
component_container_isolated
src/component_container_isolated.cpp
)
target_link_libraries(component_container_isolated PRIVATE component_manager rclcpp::rclcpp)
target_link_libraries(component_container_isolated component_manager rclcpp::rclcpp)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_link_libraries(component_container "stdc++fs")
target_link_libraries(component_container_mt "stdc++fs")
target_link_libraries(component_container_isolated "stdc++fs")
endif()
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
@@ -149,7 +145,7 @@ install(
# Install executables
install(
TARGETS component_container component_container_mt component_container_isolated component_container_event
TARGETS component_container component_container_mt component_container_isolated
RUNTIME DESTINATION lib/${PROJECT_NAME}
)
@@ -172,5 +168,9 @@ ament_export_libraries(component_manager)
# Export modern CMake targets
ament_export_targets(export_${PROJECT_NAME})
ament_export_dependencies(class_loader composition_interfaces rclcpp rcpputils rmw)
# specific order: dependents before dependencies
ament_export_dependencies(ament_index_cpp)
ament_export_dependencies(class_loader)
ament_export_dependencies(composition_interfaces)
ament_export_dependencies(rclcpp)
ament_package(CONFIG_EXTRAS rclcpp_components-extras.cmake.in)

View File

@@ -1,10 +1,10 @@
This document is a declaration of software quality for the `rclcpp_components` 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_components` package, based on the guidelines in [REP-2004](https://reps.openrobotics.org/rep-2004/).
# rclcpp_components Quality Declaration
The package `rclcpp_components` claims to be in the **Quality Level 1** category.
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]
@@ -53,7 +53,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:
@@ -191,7 +191,7 @@ It is **Quality Level 1**, see its [Quality Declaration document](https://github
## Platform Support [6]
`rclcpp_components` 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_components` 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_components/)
@@ -203,4 +203,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

@@ -57,9 +57,6 @@ macro(rclcpp_components_register_node target)
message(STATUS "Setting executor non-default value ${executor}")
endif()
if("${ARGS_PLUGIN}" MATCHES "^[^:]+:[^:]+$")
message(FATAL_ERROR "PLUGIN argument '${ARGS_PLUGIN}' appears to be incorrect. (e.g., 'package_name::ClassName').")
endif()
set(component ${ARGS_PLUGIN})
set(node ${ARGS_EXECUTABLE})
_rclcpp_components_register_package_hook()

View File

@@ -43,13 +43,10 @@
#include <map>
#include <memory>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
#include "class_loader/class_loader.hpp"
#include "composition_interfaces/srv/load_node.hpp"
#include "composition_interfaces/srv/unload_node.hpp"
#include "composition_interfaces/srv/list_nodes.hpp"
@@ -59,10 +56,12 @@
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_components/node_factory.hpp"
#include "rclcpp_components/node_instance_wrapper.hpp"
#include "rclcpp_components/visibility_control.hpp"
#include "rmw/types.h"
namespace class_loader
{
class ClassLoader;
} // namespace class_loader
namespace rclcpp_components
{

View File

@@ -16,22 +16,15 @@
#ifndef RCLCPP_COMPONENTS__COMPONENT_MANAGER_ISOLATED_HPP__
#define RCLCPP_COMPONENTS__COMPONENT_MANAGER_ISOLATED_HPP__
#include <atomic>
#include <chrono>
#include <map>
#include <memory>
#include <string>
#include <thread>
#include <unordered_map>
#include <utility>
#include <vector>
#include <system_error>
#include <unordered_map>
#include "rclcpp/executor.hpp"
#include "rclcpp/executors/single_threaded_executor.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp_components/component_manager.hpp"
#include "rcpputils/thread_name.hpp"
namespace rclcpp_components
{
@@ -84,16 +77,8 @@ protected:
DedicatedExecutorWrapper & wrapper = result.first->second;
wrapper.executor = exec;
auto & thread_initialized = wrapper.thread_initialized;
auto name = node_wrappers_[node_id].get_node_base_interface()->get_name();
// Copy name so that it doesn't deallocate before the thread is started
wrapper.thread = std::thread(
[exec, &thread_initialized, name]() {
try {
rcpputils::set_thread_name(name);
} catch (const std::system_error & e) {
RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Failed to set thread name: %s (%s)", e.what(),
e.code().message().c_str());
}
[exec, &thread_initialized]() {
thread_initialized = true;
exec->spin();
});

View File

@@ -18,10 +18,7 @@
#include <functional>
#include <memory>
#include "rclcpp/node_options.hpp"
#include "rclcpp_components/node_factory.hpp"
#include "rclcpp_components/node_instance_wrapper.hpp"
namespace rclcpp_components
{

View File

@@ -16,7 +16,6 @@
#define RCLCPP_COMPONENTS__REGISTER_NODE_MACRO_HPP__
#include "class_loader/class_loader.hpp"
#include "rclcpp_components/node_factory.hpp"
#include "rclcpp_components/node_factory_template.hpp"
/// Register a component that can be dynamically loaded at runtime.

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_components</name>
<version>30.1.2</version>
<version>29.5.7</version>
<description>Package containing tools for dynamically loadable components</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
@@ -16,32 +16,23 @@
<buildtool_depend>ament_cmake_ros</buildtool_depend>
<build_export_depend>class_loader</build_export_depend>
<build_export_depend>composition_interfaces</build_export_depend>
<build_export_depend>rclcpp</build_export_depend>
<build_export_depend>rcpputils</build_export_depend>
<build_export_depend>rmw</build_export_depend>
<build_depend>ament_index_cpp</build_depend>
<build_depend>class_loader</build_depend>
<build_depend>composition_interfaces</build_depend>
<build_depend>rclcpp</build_depend>
<build_depend>rcl_interfaces</build_depend>
<build_depend>rcpputils</build_depend>
<build_depend>rmw</build_depend>
<exec_depend>ament_index_cpp</exec_depend>
<exec_depend>class_loader</exec_depend>
<exec_depend>composition_interfaces</exec_depend>
<exec_depend>rclcpp</exec_depend>
<exec_depend>rcl_interfaces</exec_depend>
<exec_depend>rcpputils</exec_depend>
<exec_depend>rmw</exec_depend>
<test_depend>ament_cmake_google_benchmark</test_depend>
<test_depend>ament_cmake_gtest</test_depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<test_depend>launch_testing</test_depend>
<test_depend>std_msgs</test_depend>
<export>
<build_type>ament_cmake</build_type>

View File

@@ -14,8 +14,7 @@
#include <memory>
#include "rclcpp/executors/single_threaded_executor.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_components/component_manager.hpp"
@@ -27,6 +26,4 @@ int main(int argc, char * argv[])
auto node = std::make_shared<rclcpp_components::ComponentManager>(exec);
exec->add_node(node);
exec->spin();
return 0;
}

View File

@@ -1,32 +0,0 @@
// Copyright 2025 Open Source Robotics Foundation, Inc.Add commentMore actions
//
// 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.Add commentMore actions
#include <memory>
#include "rclcpp/utilities.hpp"
#include "rclcpp/experimental/executors/events_executor/events_executor.hpp"
#include "rclcpp_components/component_manager.hpp"
int main(int argc, char * argv[])
{
/// Component container with an events executor.
rclcpp::init(argc, argv);
auto exec = std::make_shared<rclcpp::experimental::executors::EventsExecutor>();
auto node = std::make_shared<rclcpp_components::ComponentManager>(exec);
exec->add_node(node);
exec->spin();
return 0;
}

View File

@@ -16,10 +16,8 @@
#include <vector>
#include <string>
#include "rclcpp/executors/single_threaded_executor.hpp"
#include "rclcpp/executors/multi_threaded_executor.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp_components/component_manager_isolated.hpp"
int main(int argc, char * argv[])
@@ -48,6 +46,4 @@ int main(int argc, char * argv[])
}
exec->add_node(node);
exec->spin();
return 0;
}

View File

@@ -14,8 +14,7 @@
#include <memory>
#include "rclcpp/executors/multi_threaded_executor.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_components/component_manager.hpp"
@@ -36,6 +35,4 @@ int main(int argc, char * argv[])
}
exec->add_node(node);
exec->spin();
return 0;
}

View File

@@ -17,29 +17,15 @@
#include <filesystem>
#include <functional>
#include <memory>
#include <stdexcept>
#include <sstream>
#include <string>
#include <thread>
#include <utility>
#include <vector>
#include "ament_index_cpp/get_resource.hpp"
#include "class_loader/class_loader.hpp"
#include "rclcpp/node_options.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp_components/node_factory.hpp"
#include "rcl_interfaces/msg/parameter_descriptor.hpp"
#include "rcl_interfaces/msg/integer_range.hpp"
#include "rcpputils/filesystem_helper.hpp"
#include "rcpputils/split.hpp"
#include "rmw/types.h"
using namespace std::placeholders;
namespace rclcpp_components

View File

@@ -3,33 +3,35 @@ Changelog for package rclcpp_lifecycle
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30.1.2 (2025-10-21)
29.5.7 (2026-02-09)
-------------------
30.1.1 (2025-09-11)
-------------------
* deprecate rclcpp::spin_some and rclcpp::spin_all (`#2848 <https://github.com/ros2/rclcpp/issues/2848>`_)
* Clearer warning message, the old one lacked information and was perhaps misleading (`#2927 <https://github.com/ros2/rclcpp/issues/2927>`_)
* Contributors: Alberto Soragna, Peter Mitrano (AR)
30.1.0 (2025-07-29)
-------------------
* fix cmake deprecation (`#2914 <https://github.com/ros2/rclcpp/issues/2914>`_)
cmake version < then 3.10 is deprecated
* Contributors: mosfet80
30.0.0 (2025-07-01)
29.5.6 (2025-12-23)
-------------------
29.6.1 (2025-06-23)
29.5.5 (2025-11-18)
-------------------
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_)
* introduce rcl_lifecycle_get_transition_label_by_id(). (`#2827 <https://github.com/ros2/rclcpp/issues/2827>`_)
* Contributors: Alejandro Hernández Cordero, Tomoya Fujita
* Fix REP url locations (`#2987 <https://github.com/ros2/rclcpp/issues/2987>`_) (`#2989 <https://github.com/ros2/rclcpp/issues/2989>`_)
* Add get_parameter_or overload returning value or alternative (`#2973 <https://github.com/ros2/rclcpp/issues/2973>`_) (`#2976 <https://github.com/ros2/rclcpp/issues/2976>`_)
* Contributors: mergify[bot]
29.6.0 (2025-04-25)
29.5.4 (2025-10-21)
-------------------
29.5.3 (2025-09-11)
-------------------
* Clearer warning message, the old one lacked information and was perhaps misleading (`#2927 <https://github.com/ros2/rclcpp/issues/2927>`_) (`#2931 <https://github.com/ros2/rclcpp/issues/2931>`_)
* fix cmake deprecation (`#2914 <https://github.com/ros2/rclcpp/issues/2914>`_) (`#2915 <https://github.com/ros2/rclcpp/issues/2915>`_)
* Contributors: mergify[bot]
29.5.2 (2025-07-07)
-------------------
29.5.1 (2025-06-23)
-------------------
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_) (`#2855 <https://github.com/ros2/rclcpp/issues/2855>`_)
* Contributors: mergify[bot]
29.5.0 (2025-04-18)
-------------------

View File

@@ -1,10 +1,10 @@
This document is a declaration of software quality for the `rclcpp_lifecycle` 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_lifecycle` package, based on the guidelines in [REP-2004](https://reps.openrobotics.org/rep-2004/).
# rclcpp_lifecycle Quality Declaration
The package `rclcpp_lifecycle` claims to be in the **Quality Level 1** category when 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]
@@ -53,7 +53,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:
@@ -191,7 +191,7 @@ It is **Quality Level 1**, see its [Quality Declaration document](https://github
## Platform Support [6]
`rclcpp_lifecycle` 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_lifecycle` 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_lifecycle/)
@@ -203,4 +203,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

@@ -486,6 +486,16 @@ public:
ParameterT & value,
const ParameterT & alternative_value) const;
/// Return the parameter value, or the "alternative_value" if not set.
/**
* \sa rclcpp::Node::get_parameter_or
*/
template<typename ParameterT>
ParameterT
get_parameter_or(
const std::string & name,
const ParameterT & alternative_value) const;
/// Return the parameters by the given parameter names.
/**
* \sa rclcpp::Node::get_parameters

View File

@@ -306,5 +306,16 @@ LifecycleNode::get_parameter_or(
return got_parameter;
}
template<typename ParameterT>
ParameterT
LifecycleNode::get_parameter_or(
const std::string & name,
const ParameterT & alternative_value) const
{
ParameterT parameter;
get_parameter_or(name, parameter, alternative_value);
return parameter;
}
} // namespace rclcpp_lifecycle
#endif // RCLCPP_LIFECYCLE__LIFECYCLE_NODE_IMPL_HPP_

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_lifecycle</name>
<version>30.1.2</version>
<version>29.5.7</version>
<description>Package containing a prototype for lifecycle implementation</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -414,14 +414,10 @@ LifecycleNode::LifecycleNodeInterfaceImpl::change_state(
rcl_lifecycle_trigger_transition_by_id(
&state_machine_, transition_id, publish_update) != RCL_RET_OK)
{
const char * transition_label = rcl_lifecycle_get_transition_label_by_id(
&state_machine_.transition_map, transition_id);
RCLCPP_ERROR(
node_logging_interface_->get_logger(),
"Unable to start transition %u (%s) from current state %s: %s",
transition_id,
transition_label ? transition_label : "unknown transition",
state_machine_.current_state->label, rcl_get_error_string().str);
"Unable to start transition %u from current state %s: %s",
transition_id, state_machine_.current_state->label, rcl_get_error_string().str);
rcutils_reset_error();
return RCL_RET_ERROR;
}

View File

@@ -840,6 +840,26 @@ TEST_F(TestDefaultStateMachine, check_parameters) {
EXPECT_TRUE(parameter.as_bool());
}
TEST_F(TestDefaultStateMachine, test_get_parameter_or) {
auto test_node = std::make_shared<EmptyLifecycleNode>("testnode");
const std::string param_name = "test_param";
int param_int = -999;
// Parameter does not exist, should return "or" value
EXPECT_FALSE(test_node->get_parameter_or(param_name, param_int, 123));
EXPECT_EQ(param_int, 123);
EXPECT_EQ(test_node->get_parameter_or(param_name, 456), 456);
// Declare param_int
test_node->declare_parameter(param_name, rclcpp::ParameterValue(789));
// Parameter exists, should return existing value
EXPECT_TRUE(test_node->get_parameter_or(param_name, param_int, 123));
EXPECT_EQ(param_int, 789);
EXPECT_EQ(test_node->get_parameter_or(param_name, 456), 789);
}
TEST_F(TestDefaultStateMachine, test_getters) {
auto test_node = std::make_shared<EmptyLifecycleNode>("testnode");
auto options = test_node->get_node_options();

View File

@@ -226,28 +226,36 @@ private:
rclcpp::init(0, nullptr);
lifecycle_node_ = std::make_shared<EmptyLifecycleNode>();
lifecycle_client_ = std::make_shared<LifecycleServiceClient>("client");
executor_ = std::make_shared<rclcpp::executors::SingleThreadedExecutor>();
spinner_ = std::thread([this]() {
executor_->add_node(lifecycle_node_->get_node_base_interface());
executor_->add_node(lifecycle_client_);
executor_->spin();
});
spinner_ = std::thread(&TestLifecycleServiceClient::spin, this);
}
void TearDown() override
{
while(!executor_->is_spinning()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
{
std::lock_guard<std::mutex> guard(shutdown_mutex_);
rclcpp::shutdown();
}
executor_->cancel();
spinner_.join();
rclcpp::shutdown();
}
void spin()
{
while (true) {
{
std::lock_guard<std::mutex> guard(shutdown_mutex_);
if (!rclcpp::ok()) {
break;
}
rclcpp::spin_some(lifecycle_node_->get_node_base_interface());
rclcpp::spin_some(lifecycle_client_);
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
std::shared_ptr<EmptyLifecycleNode> lifecycle_node_;
std::shared_ptr<LifecycleServiceClient> lifecycle_client_;
std::shared_ptr<rclcpp::executors::SingleThreadedExecutor> executor_;
std::mutex shutdown_mutex_;
std::thread spinner_;
};
@@ -447,39 +455,34 @@ TEST_F(TestLifecycleServiceClientRCLErrors, call_services_rcl_errors) {
auto mock = mocking_utils::patch_and_return(
"lib:rclcpp_lifecycle", rcl_lifecycle_state_machine_is_initialized, RCL_RET_ERROR);
rclcpp::executors::SingleThreadedExecutor lifecycle_node_executor;
lifecycle_node_executor.add_node(lifecycle_node->get_node_base_interface());
rclcpp::executors::SingleThreadedExecutor client_executor;
client_executor.add_node(lifecycle_client);
// on_change_state
lifecycle_client->change_state(
lifecycle_msgs::msg::Transition::TRANSITION_CONFIGURE);
client_executor.spin_some();
rclcpp::spin_some(lifecycle_client);
EXPECT_THROW(
lifecycle_node_executor.spin_some(), std::runtime_error);
rclcpp::spin_some(lifecycle_node->get_node_base_interface()), std::runtime_error);
// on_get_state
lifecycle_client->get_state();
client_executor.spin_some();
rclcpp::spin_some(lifecycle_client);
EXPECT_THROW(
lifecycle_node_executor.spin_some(), std::runtime_error);
rclcpp::spin_some(lifecycle_node->get_node_base_interface()), std::runtime_error);
// on_get_avilable_states
lifecycle_client->get_available_states();
client_executor.spin_some();
rclcpp::spin_some(lifecycle_client);
EXPECT_THROW(
lifecycle_node_executor.spin_some(), std::runtime_error);
rclcpp::spin_some(lifecycle_node->get_node_base_interface()), std::runtime_error);
// on_get_available_transitions
lifecycle_client->get_available_transitions();
client_executor.spin_some();
rclcpp::spin_some(lifecycle_client);
EXPECT_THROW(
lifecycle_node_executor.spin_some(), std::runtime_error);
rclcpp::spin_some(lifecycle_node->get_node_base_interface()), std::runtime_error);
// on_get_transition_graph
lifecycle_client->get_transition_graph();
client_executor.spin_some();
rclcpp::spin_some(lifecycle_client);
EXPECT_THROW(
lifecycle_node_executor.spin_some(), std::runtime_error);
rclcpp::spin_some(lifecycle_node->get_node_base_interface()), std::runtime_error);
}