Compare commits

..

34 Commits

Author SHA1 Message Date
Jacob Perron
cb4bdb7b19 1.0.0 2020-05-12 14:05:31 -07:00
Ivan Santiago Paunovic
803d7f27be Remove MANUAL_BY_NODE liveliness API (#1107)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-05-12 14:52:26 -03:00
brawner
cac761373f Increasing test coverage of rclcpp_components (#1044)
* Increasing test coverage of rclcpp_components

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* PR fixup

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Fixup

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Removing throws test for now

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-05-12 10:26:49 -07:00
Karsten Knese
66114c3a4a use rosidl_default_generators dependency in test (#1114)
Signed-off-by: Karsten Knese <karsten@openrobotics.org>
2020-05-12 08:29:45 -07:00
Chris Lalancette
ccf2f1c760 Make sure to include what you use. (#1112)
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2020-05-11 13:32:49 -04:00
Louise Poubel
846e4ce9d3 Mark flaky test with xfail: TestMultiThreadedExecutor (#1109)
Signed-off-by: Louise Poubel <louise@openrobotics.org>
2020-05-11 09:16:04 -07:00
Karsten Knese
e24f402238 avoid callback_group deprecation (#1108)
Signed-off-by: Karsten Knese <karsten@openrobotics.org>
2020-05-08 09:04:38 -07:00
Chris Lalancette
4d1de47df3 0.9.1 2020-05-08 15:40:05 +00:00
Chris Lalancette
5b1877adc4 Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2020-05-08 15:39:57 +00:00
Alejandro Hernández Cordero
e0d0e03078 Added rclcpp lifecycle Doxyfile (#1089)
* Added rclcpp lifecycle Doxyfile

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

* Fixed doxyfile

Signed-off-by: ahcorde <ahcorde@gmail.com>
2020-05-08 08:48:52 +02:00
Devin Bonnie
d10f7b7c62 Fix tests that were not properly torn down (#1073)
Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>
2020-05-06 13:04:45 -03:00
Alejandro Hernández Cordero
f160a8bc1d Added docblock in rclcpp (#1103)
* Added docblock in rclcpp

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

* Added feedback

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

* Added feedback

Signed-off-by: ahcorde <ahcorde@gmail.com>
2020-05-06 09:04:31 +02:00
Alejandro Hernández Cordero
e2dbc5d5d5 Added Quality declaration: rclcpp, rclpp_action, rclcpp_components andrclcpp_lifecycle (#1100)
* Added Quality declaration: rclcpp, rclpp_action, rclcpp_components, rclcpp_lifecycle

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

* Added feedback

Signed-off-by: ahcorde <ahcorde@gmail.com>
2020-05-01 22:41:22 +02:00
Ivan Santiago Paunovic
13c09acfad Use RCL_RET_SERVICE_TAKE_FAILED and not RCL_RET_CLIENT_TAKE_FAILED when checking a request take (#1101)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-05-01 13:55:46 -03:00
brawner
f69b18203f Increasing test coverage of rclcpp_lifecycle (#1045)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-04-30 10:29:45 -07:00
Christophe Bedard
ef6434026f Update comment about return value in Executor::get_next_ready_executable (#1085)
Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
2020-04-30 10:27:52 -03:00
Jacob Perron
1c943d16fc 0.9.0 2020-04-29 22:44:16 -07:00
brawner
e6325839f1 Increasing test coverage of rclcpp_action (#1043)
* Increasing test coverage of rclcpp_action

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* PR Fixup

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* PR Fixup

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* PR Fixup

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Increasing test coverage of rclcpp_action

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* PR Fixup

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* PR Fixup

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* PR Fixup

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Fix warnings

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-04-29 14:25:52 -07:00
Alejandro Hernández Cordero
9150201d28 Added rclcpp_components Doxyfile (#1091)
* Added rclcpp components Doxyfile

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

* Added feedback

Signed-off-by: ahcorde <ahcorde@gmail.com>
2020-04-29 08:45:04 +02:00
Karsten Knese
c1b80bd367 Serialized message move constructor (#1097)
* correct use of move semantics

Signed-off-by: Knese Karsten <karsten@openrobotics.org>

* more tests

Signed-off-by: Knese Karsten <karsten@openrobotics.org>

* make error message more exact

Signed-off-by: Karsten Knese <karsten@openrobotics.org>

* use std::exchange

Signed-off-by: Karsten Knese <karsten@openrobotics.org>

* fix typo

Signed-off-by: Karsten Knese <karsten@openrobotics.org>
2020-04-27 22:23:43 -07:00
Michel Hidalgo
814298480c Enforce a precedence for wildcard matching in parameter overrides. (#1094)
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
2020-04-27 15:14:48 -03:00
Dirk Thomas
45f3976453 export targets in a addition to include directories / libraries (#1096)
Signed-off-by: Dirk Thomas <dirk-thomas@users.noreply.github.com>
2020-04-27 10:30:33 -07:00
brawner
e0bf4a9c20 Add serialized_message.hpp header (#1095)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-04-26 21:40:40 -07:00
Prajakta Gokhale
04f3c33de5 Add received message age metric to topic statistics (#1080)
* Add received message age metric to topic statistics

Signed-off-by: Prajakta Gokhale <prajaktg@amazon.com>

* Add unit tests

Signed-off-by: Prajakta Gokhale <prajaktg@amazon.com>

* Add IMU messages in unit test

Signed-off-by: Prajakta Gokhale <prajaktg@amazon.com>

* Use system time instead of steady time
Test received message age stats values are greater than 0

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Fix test warnings

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Replace IMU messages with new dummy messages

Signed-off-by: Prajakta Gokhale <prajaktg@amazon.com>

* Remove outdated TODO and unused test variables

Signed-off-by: Prajakta Gokhale <prajaktg@amazon.com>

* Address review comments

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Address review comments

Signed-off-by: Prajakta Gokhale <prajaktg@amazon.com>

* Re-add message with header for unit testing

Signed-off-by: Prajakta Gokhale <prajaktg@amazon.com>

* Address message review feedback

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Remove extra newline

Signed-off-by: Prajakta Gokhale <prajaktg@amazon.com>

* Address more review feedback

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Fix Windows failure

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Only set append_library_dirs once

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>
2020-04-23 20:41:35 -07:00
William Woodall
df3c2ffa8a deprecate redundant namespaces (#1083)
* deprecate redundant namespaces, move classes to own files, rename some classes

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

* fixup

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

* address review comments

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

* fix ups since rebase

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

* avoid deprecation warnings from deprecated functions

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

* more fixes

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

* another fixup, after another rebase

Signed-off-by: William Woodall <william@osrfoundation.org>
2020-04-23 15:28:45 -07:00
Dirk Thomas
52ae3e0337 export targets in a addition to include directories / libraries (#1088)
Signed-off-by: Dirk Thomas <dirk-thomas@users.noreply.github.com>
2020-04-23 14:18:51 -07:00
Ivan Santiago Paunovic
80e8dcad02 Ensure logging is initialized just once (#998)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-04-23 17:33:56 -03:00
Karsten Knese
e64022f753 adapt subscription traits to rclcpp::SerializedMessage (#1092)
Signed-off-by: Karsten Knese <karsten@openrobotics.org>
2020-04-23 15:09:40 -03:00
tomoya
c3d599fc8c protect subscriber_statistics_collectors_ with a mutex (#1084)
* subscriber_statistics_collectors_ should be protected with mutex.

Co-Authored-By: William Woodall <william+github@osrfoundation.org>
Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2020-04-22 23:55:04 -07:00
Devin Bonnie
cdeed8903d Remove unused test variable (#1087)
Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>
2020-04-22 21:45:50 -07:00
Karsten Knese
46cfe84b14 Use serialized message (#1081)
* use serialized message in callback

Signed-off-by: Karsten Knese <karsten@openrobotics.org>

* introduce resize method for serialized message

Signed-off-by: Karsten Knese <karsten@openrobotics.org>

* introduce release for serialized message

Signed-off-by: Karsten Knese <karsten@openrobotics.org>

* address review comments

Signed-off-by: Karsten Knese <karsten@openrobotics.org>

* correct typo

Signed-off-by: Karsten Knese <karsten@openrobotics.org>

* fix interface traits test

Signed-off-by: Karsten Knese <karsten@openrobotics.org>
2020-04-22 19:30:56 -07:00
Devin Bonnie
bb91b6c2ef Integrate topic statistics (#1072)
* Add SubscriberTopicStatistics class

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Add SubscriberTopicStatistics Test

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Address review comments

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Modify constructor to allow a node to create necessary components

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Fix docstring style

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Remove SetPublisherTimer method

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Change naming style to match rclcpp

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Address style issues

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Use rclcpp:Time

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Address review comments

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Remove unnecessary check for null publisher timer
Move anonymous namespace function to private class method

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Update message dependency

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Initial integration of Subscriber Topic Statistics

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Fix nanoseconds used for Topic Stats

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Add simple publishing test
Minor fixes

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Add test utils header

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Integrate with Topic Statistics options
Fixes after rebasing with master

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Update after rebasing

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Address minor review comments

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Move Topic Statistics instantiation to create_subscription

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Fix rebase issue
Fix topic statistics enable flag usage
Address minor formatting

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Move new timer creation method to relevant header

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Add timers interface to topic interface

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Use new create timer method

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Address review comments

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>
2020-04-22 16:09:41 -07:00
Karsten Knese
4eab2a3c60 Fix rclcpp interface traits test (#1086)
Signed-off-by: Karsten Knese <karsten@openrobotics.org>
2020-04-22 14:19:39 -07:00
Michel Hidalgo
bb8c8ff2c0 Generate node interfaces' getters and traits. (#1069)
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
Co-authored-by: Karsten Knese <karsten@openrobotics.org>
2020-04-22 17:02:02 -03:00
111 changed files with 3841 additions and 1375 deletions

View File

@@ -8,7 +8,7 @@ rclcpp provides the standard C++ API for interacting with ROS 2.
`#include "rclcpp/rclcpp.hpp"` allows use of the most common elements of the ROS 2 system.
Visit the [rclcpp API documentation](http://docs.ros2.org/eloquent/api/rclcpp/) for a complete list of its main components.
Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) for a complete list of its main components.
### Examples

View File

@@ -2,6 +2,106 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1.0.0 (2020-05-12)
------------------
* Remove MANUAL_BY_NODE liveliness API (`#1107 <https://github.com/ros2/rclcpp/issues/1107>`_)
* Use rosidl_default_generators dependency in test (`#1114 <https://github.com/ros2/rclcpp/issues/1114>`_)
* Make sure to include what you use (`#1112 <https://github.com/ros2/rclcpp/issues/1112>`_)
* Mark flaky test with xfail: TestMultiThreadedExecutor (`#1109 <https://github.com/ros2/rclcpp/issues/1109>`_)
* Contributors: Chris Lalancette, Ivan Santiago Paunovic, Karsten Knese, Louise Poubel
0.9.1 (2020-05-08)
------------------
* Fix tests that were not properly torn down (`#1073 <https://github.com/ros2/rclcpp/issues/1073>`_)
* Added docblock in rclcpp (`#1103 <https://github.com/ros2/rclcpp/issues/1103>`_)
* Added Quality declaration: rclcpp, rclpp_action, rclcpp_components andrclcpp_lifecycle (`#1100 <https://github.com/ros2/rclcpp/issues/1100>`_)
* Use RCL_RET_SERVICE_TAKE_FAILED and not RCL_RET_CLIENT_TAKE_FAILED when checking a request take (`#1101 <https://github.com/ros2/rclcpp/issues/1101>`_)
* Update comment about return value in Executor::get_next_ready_executable (`#1085 <https://github.com/ros2/rclcpp/issues/1085>`_)
* Contributors: Alejandro Hernández Cordero, Christophe Bedard, Devin Bonnie, Ivan Santiago Paunovic
0.9.0 (2020-04-29)
------------------
* Serialized message move constructor (`#1097 <https://github.com/ros2/rclcpp/issues/1097>`_)
* Enforce a precedence for wildcard matching in parameter overrides. (`#1094 <https://github.com/ros2/rclcpp/issues/1094>`_)
* Add serialized_message.hpp header (`#1095 <https://github.com/ros2/rclcpp/issues/1095>`_)
* Add received message age metric to topic statistics (`#1080 <https://github.com/ros2/rclcpp/issues/1080>`_)
* Deprecate redundant namespaces (`#1083 <https://github.com/ros2/rclcpp/issues/1083>`_)
* Export targets in addition to include directories / libraries (`#1088 <https://github.com/ros2/rclcpp/issues/1088>`_)
* Ensure logging is initialized just once (`#998 <https://github.com/ros2/rclcpp/issues/998>`_)
* Adapt subscription traits to rclcpp::SerializedMessage (`#1092 <https://github.com/ros2/rclcpp/issues/1092>`_)
* Protect subscriber_statistics_collectors\_ with a mutex (`#1084 <https://github.com/ros2/rclcpp/issues/1084>`_)
* Remove unused test variable (`#1087 <https://github.com/ros2/rclcpp/issues/1087>`_)
* Use serialized message (`#1081 <https://github.com/ros2/rclcpp/issues/1081>`_)
* Integrate topic statistics (`#1072 <https://github.com/ros2/rclcpp/issues/1072>`_)
* Fix rclcpp interface traits test (`#1086 <https://github.com/ros2/rclcpp/issues/1086>`_)
* Generate node interfaces' getters and traits (`#1069 <https://github.com/ros2/rclcpp/issues/1069>`_)
* Use composition for serialized message (`#1082 <https://github.com/ros2/rclcpp/issues/1082>`_)
* Dnae adas/serialized message (`#1075 <https://github.com/ros2/rclcpp/issues/1075>`_)
* Reflect changes in rclcpp API (`#1079 <https://github.com/ros2/rclcpp/issues/1079>`_)
* Fix build regression (`#1078 <https://github.com/ros2/rclcpp/issues/1078>`_)
* Add NodeDefault option for enabling topic statistics (`#1074 <https://github.com/ros2/rclcpp/issues/1074>`_)
* Topic Statistics: Add SubscriptionTopicStatistics class (`#1050 <https://github.com/ros2/rclcpp/issues/1050>`_)
* Add SubscriptionOptions for topic statistics (`#1057 <https://github.com/ros2/rclcpp/issues/1057>`_)
* Remove warning message from failing to register default callback (`#1067 <https://github.com/ros2/rclcpp/issues/1067>`_)
* Create a default warning for qos incompatibility (`#1051 <https://github.com/ros2/rclcpp/issues/1051>`_)
* Add WaitSet class and modify entities to work without executor (`#1047 <https://github.com/ros2/rclcpp/issues/1047>`_)
* Include what you use (`#1059 <https://github.com/ros2/rclcpp/issues/1059>`_)
* Rename rosidl_generator_cpp namespace to rosidl_runtime_cpp (`#1060 <https://github.com/ros2/rclcpp/issues/1060>`_)
* Changed rosidl_generator_c/cpp to rosidl_runtime_c/cpp (`#1014 <https://github.com/ros2/rclcpp/issues/1014>`_)
* Use constexpr for endpoint type name (`#1055 <https://github.com/ros2/rclcpp/issues/1055>`_)
* Add InvalidParameterTypeException (`#1027 <https://github.com/ros2/rclcpp/issues/1027>`_)
* Support for ON_REQUESTED_INCOMPATIBLE_QOS and ON_OFFERED_INCOMPATIBLE_QOS events (`#924 <https://github.com/ros2/rclcpp/issues/924>`_)
* Fixup clang warning (`#1040 <https://github.com/ros2/rclcpp/issues/1040>`_)
* Adding a "static" single threaded executor (`#1034 <https://github.com/ros2/rclcpp/issues/1034>`_)
* Add equality operators for QoS profile (`#1032 <https://github.com/ros2/rclcpp/issues/1032>`_)
* Remove extra vertical whitespace (`#1030 <https://github.com/ros2/rclcpp/issues/1030>`_)
* Switch IntraProcessMessage to test_msgs/Empty (`#1017 <https://github.com/ros2/rclcpp/issues/1017>`_)
* Add new type of exception that may be thrown during creation of publisher/subscription (`#1026 <https://github.com/ros2/rclcpp/issues/1026>`_)
* Don't check lifespan on publisher QoS (`#1002 <https://github.com/ros2/rclcpp/issues/1002>`_)
* Fix get_parameter_tyeps of AsyncPrameterClient results are always empty (`#1019 <https://github.com/ros2/rclcpp/issues/1019>`_)
* Cleanup node interfaces includes (`#1016 <https://github.com/ros2/rclcpp/issues/1016>`_)
* Add ifdefs to remove tracing-related calls if tracing is disabled (`#1001 <https://github.com/ros2/rclcpp/issues/1001>`_)
* Include missing header in node_graph.cpp (`#994 <https://github.com/ros2/rclcpp/issues/994>`_)
* Add missing includes of logging.hpp (`#995 <https://github.com/ros2/rclcpp/issues/995>`_)
* Zero initialize publisher GID in subscription intra process callback (`#1011 <https://github.com/ros2/rclcpp/issues/1011>`_)
* Removed ament_cmake dependency (`#989 <https://github.com/ros2/rclcpp/issues/989>`_)
* Switch to using new rcutils_strerror (`#993 <https://github.com/ros2/rclcpp/issues/993>`_)
* Ensure all rclcpp::Clock accesses are thread-safe
* Use a PIMPL for rclcpp::Clock implementation
* Replace rmw_implementation for rmw dependency in package.xml (`#990 <https://github.com/ros2/rclcpp/issues/990>`_)
* Add missing service callback registration tracepoint (`#986 <https://github.com/ros2/rclcpp/issues/986>`_)
* Rename rmw_topic_endpoint_info_array count to size (`#996 <https://github.com/ros2/rclcpp/issues/996>`_)
* Implement functions to get publisher and subcription informations like QoS policies from topic name (`#960 <https://github.com/ros2/rclcpp/issues/960>`_)
* Code style only: wrap after open parenthesis if not in one line (`#977 <https://github.com/ros2/rclcpp/issues/977>`_)
* Accept taking an rvalue ref future in spin_until_future_complete (`#971 <https://github.com/ros2/rclcpp/issues/971>`_)
* Allow node clock use in logging macros (`#969 <https://github.com/ros2/rclcpp/issues/969>`_) (`#970 <https://github.com/ros2/rclcpp/issues/970>`_)
* Change order of deprecated and visibility attributes (`#968 <https://github.com/ros2/rclcpp/issues/968>`_)
* Deprecated is_initialized() (`#967 <https://github.com/ros2/rclcpp/issues/967>`_)
* Don't specify calling convention in std::_Binder template (`#952 <https://github.com/ros2/rclcpp/issues/952>`_)
* Added missing include to logging.hpp (`#964 <https://github.com/ros2/rclcpp/issues/964>`_)
* Assigning make_shared result to variables in test (`#963 <https://github.com/ros2/rclcpp/issues/963>`_)
* Fix unused parameter warning (`#962 <https://github.com/ros2/rclcpp/issues/962>`_)
* Stop retaining ownership of the rcl context in GraphListener (`#946 <https://github.com/ros2/rclcpp/issues/946>`_)
* Clear sub contexts when starting another init-shutdown cycle (`#947 <https://github.com/ros2/rclcpp/issues/947>`_)
* Avoid possible UB in Clock jump callbacks (`#954 <https://github.com/ros2/rclcpp/issues/954>`_)
* Handle unknown global ROS arguments (`#951 <https://github.com/ros2/rclcpp/issues/951>`_)
* Mark get_clock() as override to fix clang warnings (`#939 <https://github.com/ros2/rclcpp/issues/939>`_)
* Create node clock calls const (try 2) (`#922 <https://github.com/ros2/rclcpp/issues/922>`_)
* Fix asserts on shared_ptr::use_count; expects long, got uint32 (`#936 <https://github.com/ros2/rclcpp/issues/936>`_)
* Use absolute topic name for parameter events (`#929 <https://github.com/ros2/rclcpp/issues/929>`_)
* Add enable_rosout into NodeOptions. (`#900 <https://github.com/ros2/rclcpp/issues/900>`_)
* Removing "virtual", adding "override" keywords (`#897 <https://github.com/ros2/rclcpp/issues/897>`_)
* Use weak_ptr to store context in GraphListener (`#906 <https://github.com/ros2/rclcpp/issues/906>`_)
* Complete published event message when declaring a parameter (`#928 <https://github.com/ros2/rclcpp/issues/928>`_)
* Fix duration.cpp lint error (`#930 <https://github.com/ros2/rclcpp/issues/930>`_)
* Intra-process subscriber should use RMW actual qos. (ros2`#913 <https://github.com/ros2/rclcpp/issues/913>`_) (`#914 <https://github.com/ros2/rclcpp/issues/914>`_)
* Type conversions fixes (`#901 <https://github.com/ros2/rclcpp/issues/901>`_)
* Add override keyword to functions
* Remove unnecessary virtual keywords
* Only check for new work once in spin_some (`#471 <https://github.com/ros2/rclcpp/issues/471>`_) (`#844 <https://github.com/ros2/rclcpp/issues/844>`_)
* Add addition/subtraction assignment operators to Time (`#748 <https://github.com/ros2/rclcpp/issues/748>`_)
* Contributors: Alberto Soragna, Alejandro Hernández Cordero, Barry Xu, Chris Lalancette, Christophe Bedard, Claire Wang, Dan Rose, DensoADAS, Devin Bonnie, Dino Hüllmann, Dirk Thomas, DongheeYe, Emerson Knapp, Ivan Santiago Paunovic, Jacob Perron, Jaison Titus, Karsten Knese, Matt Schickler, Miaofei Mei, Michel Hidalgo, Mikael Arguedas, Monika Idzik, Prajakta Gokhale, Roger Strain, Scott K Logan, Sean Kelly, Stephen Brawner, Steven Macenski, Steven! Ragnarök, Todd Malsbary, Tomoya Fujita, William Woodall, Zachary Michaels
0.8.3 (2019-11-19)
------------------

View File

@@ -26,8 +26,6 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
include_directories(include)
set(${PROJECT_NAME}_SRCS
src/rclcpp/any_executable.cpp
src/rclcpp/callback_group.cpp
@@ -102,23 +100,71 @@ configure_file(
COPYONLY
)
# generate header with logging macros
set(python_code
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 "${python_code}")
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 ${PYTHON_EXECUTABLE} ARGS -c "${python_code}"
COMMAND ${PYTHON_EXECUTABLE} 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)
include_directories("${CMAKE_CURRENT_BINARY_DIR}/include")
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)
# "watch" template for changes
configure_file(
"resource/interface_traits.hpp.em"
"${CMAKE_CURRENT_BINARY_DIR}/${interface_name}_traits.hpp.em.watch"
COPYONLY
)
set(python_${interface_name}_traits
"import em"
"em.invoke(['-D', 'interface_name = \\'${interface_name}\\'', '-o', 'include/rclcpp/node_interfaces/${interface_name}_traits.hpp', '${CMAKE_CURRENT_SOURCE_DIR}/resource/interface_traits.hpp.em'])")
string(REPLACE ";" "$<SEMICOLON>" python_${interface_name}_traits "${python_${interface_name}_traits}")
add_custom_command(OUTPUT include/rclcpp/node_interfaces/${interface_name}_traits.hpp
COMMAND ${CMAKE_COMMAND} -E make_directory "include/rclcpp/node_interfaces"
COMMAND ${PYTHON_EXECUTABLE} ARGS -c "${python_${interface_name}_traits}"
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${interface_name}_traits.hpp.em.watch"
COMMENT "Expanding interface_traits.hpp.em into ${interface_name}_traits.hpp"
VERBATIM
)
list(APPEND ${PROJECT_NAME}_SRCS
include/rclcpp/node_interfaces/${interface_name}_traits.hpp)
# "watch" template for changes
configure_file(
"resource/get_interface.hpp.em"
"get_${interface_name}.hpp.em.watch"
COPYONLY
)
set(python_get_${interface_name}
"import em"
"em.invoke(['-D', 'interface_name = \\'${interface_name}\\'', '-o', 'include/rclcpp/node_interfaces/get_${interface_name}.hpp', '${CMAKE_CURRENT_SOURCE_DIR}/resource/get_interface.hpp.em'])")
string(REPLACE ";" "$<SEMICOLON>" python_get_${interface_name} "${python_get_${interface_name}}")
add_custom_command(OUTPUT include/rclcpp/node_interfaces/get_${interface_name}.hpp
COMMAND ${CMAKE_COMMAND} -E make_directory "include/rclcpp/node_interfaces"
COMMAND ${PYTHON_EXECUTABLE} ARGS -c "${python_get_${interface_name}}"
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/get_${interface_name}.hpp.em.watch"
COMMENT "Expanding get_interface.hpp.em into get_${interface_file}.hpp"
VERBATIM
)
list(APPEND ${PROJECT_NAME}_SRCS
include/rclcpp/node_interfaces/get_${interface_name}.hpp)
endforeach()
add_library(${PROJECT_NAME}
${${PROJECT_NAME}_SRCS})
target_include_directories(${PROJECT_NAME} PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
"$<INSTALL_INTERFACE:include>")
# specific order: dependents before dependencies
ament_target_dependencies(${PROJECT_NAME}
"libstatistics_collector"
@@ -140,7 +186,7 @@ target_compile_definitions(${PROJECT_NAME}
PRIVATE "RCLCPP_BUILDING_LIBRARY")
install(
TARGETS ${PROJECT_NAME}
TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
@@ -149,6 +195,7 @@ install(
# specific order: dependents before dependencies
ament_export_include_directories(include)
ament_export_libraries(${PROJECT_NAME})
ament_export_targets(${PROJECT_NAME})
ament_export_dependencies(libstatistics_collector)
ament_export_dependencies(rcl)
@@ -169,6 +216,7 @@ if(BUILD_TESTING)
ament_lint_auto_find_test_dependencies()
find_package(rmw_implementation_cmake REQUIRED)
find_package(rosidl_default_generators REQUIRED)
find_package(test_msgs REQUIRED)
@@ -176,6 +224,14 @@ if(BUILD_TESTING)
add_definitions(-DTEST_RESOURCES_DIRECTORY="${CMAKE_CURRENT_BINARY_DIR}/test/resources")
rosidl_generate_interfaces(${PROJECT_NAME}_test_msgs
test/msg/Header.msg
test/msg/MessageWithHeader.msg
DEPENDENCIES builtin_interfaces
LIBRARY_NAME ${PROJECT_NAME}
SKIP_INSTALL
)
ament_add_gtest(test_client test/test_client.cpp)
if(TARGET test_client)
ament_target_dependencies(test_client
@@ -210,6 +266,7 @@ if(BUILD_TESTING)
endif()
ament_add_gtest(test_function_traits test/test_function_traits.cpp)
if(TARGET test_function_traits)
target_include_directories(test_function_traits PUBLIC include)
ament_target_dependencies(test_function_traits
"rcl_interfaces"
"rmw"
@@ -533,12 +590,21 @@ if(BUILD_TESTING)
target_link_libraries(test_init ${PROJECT_NAME})
endif()
ament_add_gtest(test_interface_traits test/test_interface_traits.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_interface_traits)
ament_target_dependencies(test_interface_traits
"rcl")
target_link_libraries(test_interface_traits ${PROJECT_NAME})
endif()
ament_add_gtest(test_multi_threaded_executor test/executors/test_multi_threaded_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_multi_threaded_executor)
ament_target_dependencies(test_multi_threaded_executor
"rcl")
target_link_libraries(test_multi_threaded_executor ${PROJECT_NAME})
ament_add_test_label(test_multi_threaded_executor xfail)
endif()
ament_add_gtest(test_guard_condition test/test_guard_condition.cpp
@@ -554,9 +620,12 @@ if(BUILD_TESTING)
target_link_libraries(test_wait_set ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_topic_statistics test/topic_statistics/test_subscription_topic_statistics.cpp)
ament_add_gtest(test_subscription_topic_statistics test/topic_statistics/test_subscription_topic_statistics.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}"
)
if(TARGET test_subscription_topic_statistics)
ament_target_dependencies(test_subscription_topic_statistics
"builtin_interfaces"
"libstatistics_collector"
"rcl_interfaces"
"rcutils"
@@ -565,6 +634,7 @@ if(BUILD_TESTING)
"rosidl_typesupport_cpp"
"statistics_msgs"
"test_msgs")
rosidl_target_interfaces(test_subscription_topic_statistics ${PROJECT_NAME}_test_msgs "rosidl_typesupport_cpp")
target_link_libraries(test_subscription_topic_statistics ${PROJECT_NAME})
endif()

View File

@@ -0,0 +1,173 @@
This document is a declaration of software quality for the `rclcpp` package, based on the guidelines in [REP-2004](https://github.com/ros-infrastructure/rep/blob/rep-2004/rep-2004.rst).
# `rclcpp` Quality Declaration
The package `rclcpp` claims to be in the **Quality Level 4** category.
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#package-quality-categories) of the ROS2 developer guide.
## Version Policy [1]
### Version Scheme [1.i]
`rclcpp` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#versioning)
### Version Stability [1.ii]
`rclcpp` is not yet at a stable version, i.e. `>= 1.0.0`.
The current version can be found in its [package.xml](package.xml), and its change history can be found in its [CHANGELOG](CHANGELOG.rst).
### Public API Declaration [1.iii]
All symbols in the installed headers are considered part of the public API.
Except for the exclusions listed below, all installed headers are in the `include` directory of the package, headers in any other folders are not installed and considered private.
Headers under the folder `experimental` are not considered part of the public API as they have not yet been stabilized. These symbols are namespaced `rclcpp::experimental`.
Headers under the folder `detail` are not considered part of the public API and are subject to change without notice. These symbols are namespaced `rclcpp::detail`.
### API Stability Policy [1.iv]
`rclcpp` will not break public API within a released ROS distribution, i.e. no major releases once the ROS distribution is released.
### ABI Stability Policy [1.v]
`rclcpp` contains C++ code and therefore must be concerned with ABI stability, and will maintain ABI stability within a ROS distribution.
### ABI and ABI Stability Within a Released ROS Distribution [1.vi]
`rclcpp` will not break API nor ABI within a released ROS distribution, i.e. no major releases once the ROS distribution is released.
## Change Control Process [2]
`rclcpp` follows the recommended guidelines for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process).
### Change Requests [2.i]
All changes will occur through a pull request, check [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process) for additional information.
### Contributor Origin [2.ii]
This package uses DCO as its confirmation of contributor origin policy. More information can be found in [CONTRIBUTING](../CONTRIBUTING.md).
### Peer Review Policy [2.iii]
All pull requests will be peer-reviewed, check [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process) for additional information.
### Continuous Integration [2.iv]
All pull requests must pass CI on all [tier 1 platforms](https://www.ros.org/reps/rep-2000.html#support-tiers)
Currently nightly results can be seen here:
* [linux-aarch64_release](https://ci.ros2.org/view/nightly/job/nightly_linux-aarch64_release/lastBuild/testReport/rclcpp/)
* [linux_release](https://ci.ros2.org/view/nightly/job/nightly_linux_release/lastBuild/testReport/rclcpp/)
* [mac_osx_release](https://ci.ros2.org/view/nightly/job/nightly_osx_release/lastBuild/testReport/rclcpp/)
* [windows_release](https://ci.ros2.org/view/nightly/job/nightly_win_rel/lastBuild/testReport/rclcpp/)
### Documentation Policy [2.v]
All pull requests must resolve related documentation changes before merging.
## Documentation [3]
### Feature Documentation [3.i]
`rclcpp` has a [feature list](http://docs.ros2.org/latest/api/rclcpp/) and each item in the list links to the corresponding feature documentation. There is documentation for all of the features, and new features require documentation before being added.
### Public API Documentation [3.ii]
The API is publicly available in the [ROS 2 API documentation](http://docs.ros2.org/latest/api/rclcpp/).
### License [3.iii]
The license for `rclcpp` is Apache 2.0, and a summary is in each source file, the type is declared in the [`package.xml`](./package.xml) manifest file, and a full copy of the license is in the [`LICENSE`](../LICENSE) file.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Epr/job/Epr__rclcpp__ubuntu_bionic_amd64/lastBuild/testReport/rclcpp/) can be found a list with the latest results of the various linters being run on the package.
### Copyright Statements [3.iv]
The copyright holders each provide a statement of copyright in each source code file in `rclcpp`.
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Epr/job/Epr__rclcpp__ubuntu_bionic_amd64/lastBuild/testReport/rclcpp/copyright/).
## Testing [4]
### Feature Testing [4.i]
Each feature in `rclcpp` has corresponding tests which simulate typical usage, and they are located in the [`test`](https://github.com/ros2/rclcpp/tree/master/test) directory.
New features are required to have tests before being added.
Currently nightly test results can be seen here:
* [linux-aarch64_release](https://ci.ros2.org/view/nightly/job/nightly_linux-aarch64_release/lastBuild/testReport/rclcpp/)
* [linux_release](https://ci.ros2.org/view/nightly/job/nightly_linux_release/lastBuild/testReport/rclcpp/)
* [mac_osx_release](https://ci.ros2.org/view/nightly/job/nightly_osx_release/lastBuild/testReport/rclcpp/)
* [windows_release](https://ci.ros2.org/view/nightly/job/nightly_win_rel/lastBuild/testReport/rclcpp/)
### Public API Testing [4.ii]
Each part of the public API has tests, and new additions or changes to the public API require tests before being added.
The tests aim to cover both typical usage and corner cases, but are quantified by contributing to code coverage.
### Coverage [4.iii]
`rclcpp` follows the recommendations for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#code-coverage), and opts to use line coverage instead of branch coverage.
This includes:
- tracking and reporting line coverage statistics
- achieving and maintaining a reasonable branch line coverage (90-100%)
- no lines are manually skipped in coverage calculations
Changes are required to make a best effort to keep or increase coverage before being accepted, but decreases are allowed if properly justified and accepted by reviewers.
### Performance [4.iv]
It is not yet defined if this package requires performance testing and how addresses this topic.
### Linters and Static Analysis [4.v]
`rclcpp` uses and passes all the ROS2 standard linters and static analysis tools for a C++ package as described in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#linters-and-static-analysis). Passing implies there are no linter/static errors when testing against CI of supported platforms.
Currently nightly test results can be seen here:
* [linux-aarch64_release](https://ci.ros2.org/view/nightly/job/nightly_linux-aarch64_release/lastBuild/testReport/rclcpp/)
* [linux_release](https://ci.ros2.org/view/nightly/job/nightly_linux_release/lastBuild/testReport/rclcpp/)
* [mac_osx_release](https://ci.ros2.org/view/nightly/job/nightly_osx_release/lastBuild/testReport/rclcpp/)
* [windows_release](https://ci.ros2.org/view/nightly/job/nightly_win_rel/lastBuild/testReport/rclcpp/)
## Dependencies [5]
### Direct and Optional Runtime ROS Dependencies [5.i]/[5.ii]
`rclcpp` has the following runtime ROS dependencies:
- libstatistics_collector
- rcl
- rcl_yaml_param_parser
- rcpputils
- rcutils
- rmw
- statistics_msgs
- tracetools
It has several "buildtool" dependencies, which do not affect the resulting quality of the package, because they do not contribute to the public library API.
It also has several test dependencies, which do not affect the resulting quality of the package, because they are only used to build and run the test code.
### Direct Runtime non-ROS Dependency [5.iii]
`rclcpp` has no run-time or build-time dependencies that need to be considered for this declaration.
## 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.
Currently nightly build status can be seen here:
* [linux-aarch64_release](https://ci.ros2.org/view/nightly/job/nightly_linux-aarch64_release/lastBuild/rclcpp/)
* [linux_release](https://ci.ros2.org/view/nightly/job/nightly_linux_release/lastBuild/rclcpp/)
* [mac_osx_release](https://ci.ros2.org/view/nightly/job/nightly_osx_release/lastBuild/rclcpp/)
* [windows_release](https://ci.ros2.org/view/nightly/job/nightly_win_rel/lastBuild/rclcpp/)
## Security
### Vulnerability Disclosure Policy [7.i]
This package does not yet have a Vulnerability Disclosure Policy

7
rclcpp/README.md Normal file
View File

@@ -0,0 +1,7 @@
# `rclcpp`
The ROS client library in C++. Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) for a complete list of its main components.
## Quality Declaration
This package claims to be in the **Quality Level 4** category, see the [Quality Declaration](QUALITY_DECLARATION.md) for more details.

View File

@@ -84,22 +84,42 @@ public:
bool
take_type_erased_response(void * response_out, rmw_request_id_t & request_header_out);
/// Return the name of the service.
/** \return The name of the service. */
RCLCPP_PUBLIC
const char *
get_service_name() const;
/// Return the rcl_client_t client handle in a std::shared_ptr.
/**
* This handle remains valid after the Client is destroyed.
* The actual rcl client is not finalized until it is out of scope everywhere.
*/
RCLCPP_PUBLIC
std::shared_ptr<rcl_client_t>
get_client_handle();
/// Return the rcl_client_t client handle in a std::shared_ptr.
/**
* This handle remains valid after the Client is destroyed.
* The actual rcl client is not finalized until it is out of scope everywhere.
*/
RCLCPP_PUBLIC
std::shared_ptr<const rcl_client_t>
get_client_handle() const;
/// Return if the service is ready.
/**
* \return `true` if the service is ready, `false` otherwise
*/
RCLCPP_PUBLIC
bool
service_is_ready() const;
/// Wait for a service to be ready.
/**
* \param timeout maximum time to wait
*/
template<typename RepT = int64_t, typename RatioT = std::milli>
bool
wait_for_service(

View File

@@ -89,6 +89,7 @@ public:
bool
ros_time_is_active();
/// Return the rcl_clock_t clock handle
RCLCPP_PUBLIC
rcl_clock_t *
get_clock_handle() noexcept;
@@ -97,6 +98,7 @@ public:
rcl_clock_type_t
get_clock_type() const noexcept;
/// Get the clock's mutex
RCLCPP_PUBLIC
std::mutex &
get_clock_mutex() noexcept;

View File

@@ -338,6 +338,9 @@ private:
rclcpp::InitOptions init_options_;
std::string shutdown_reason_;
// Keep shared ownership of global logging configure mutex.
std::shared_ptr<std::mutex> logging_configure_mutex_;
std::unordered_map<std::type_index, std::shared_ptr<void>> sub_contexts_;
// This mutex is recursive so that the constructor of a sub context may
// attempt to acquire another sub context.

View File

@@ -15,15 +15,25 @@
#ifndef RCLCPP__CREATE_SUBSCRIPTION_HPP_
#define RCLCPP__CREATE_SUBSCRIPTION_HPP_
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include "rclcpp/detail/resolve_enable_topic_statistics.hpp"
#include "rclcpp/node_interfaces/get_node_timers_interface.hpp"
#include "rclcpp/node_interfaces/get_node_topics_interface.hpp"
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/create_timer.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/subscription_factory.hpp"
#include "rclcpp/subscription_options.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/timer.hpp"
#include "rclcpp/topic_statistics/subscription_topic_statistics.hpp"
#include "rmw/qos_profiles.h"
namespace rclcpp
@@ -64,10 +74,46 @@ create_subscription(
using rclcpp::node_interfaces::get_node_topics_interface;
auto node_topics = get_node_topics_interface(std::forward<NodeT>(node));
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>>
subscription_topic_stats = nullptr;
if (rclcpp::detail::resolve_enable_topic_statistics(
options,
*node_topics->get_node_base_interface()))
{
std::shared_ptr<Publisher<statistics_msgs::msg::MetricsMessage>> publisher =
create_publisher<statistics_msgs::msg::MetricsMessage>(
node,
options.topic_stats_options.publish_topic,
qos);
subscription_topic_stats = std::make_shared<
rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>
>(node_topics->get_node_base_interface()->get_name(), publisher);
auto sub_call_back = [subscription_topic_stats]() {
subscription_topic_stats->publish_message();
};
auto node_timer_interface = node_topics->get_node_timers_interface();
auto timer = create_wall_timer(
std::chrono::duration_cast<std::chrono::nanoseconds>(
options.topic_stats_options.publish_period),
sub_call_back,
options.callback_group,
node_topics->get_node_base_interface(),
node_timer_interface
);
subscription_topic_stats->set_publisher_timer(timer);
}
auto factory = rclcpp::create_subscription_factory<MessageT>(
std::forward<CallbackT>(callback),
options,
msg_mem_strat
msg_mem_strat,
subscription_topic_stats
);
auto sub = node_topics->create_subscription(topic_name, factory, qos);

View File

@@ -15,6 +15,8 @@
#ifndef RCLCPP__CREATE_TIMER_HPP_
#define RCLCPP__CREATE_TIMER_HPP_
#include <chrono>
#include <exception>
#include <memory>
#include <string>
#include <utility>
@@ -32,8 +34,8 @@ namespace rclcpp
template<typename CallbackT>
typename rclcpp::TimerBase::SharedPtr
create_timer(
node_interfaces::NodeBaseInterface * node_base,
node_interfaces::NodeTimersInterface * node_timers,
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
std::shared_ptr<node_interfaces::NodeTimersInterface> node_timers,
rclcpp::Clock::SharedPtr clock,
rclcpp::Duration period,
CallbackT && callback,
@@ -68,6 +70,46 @@ create_timer(
group);
}
/// Convenience method to create a timer with node resources.
/**
*
* \tparam DurationRepT
* \tparam DurationT
* \tparam CallbackT
* \param period period to exectute callback
* \param callback callback to execute via the timer period
* \param group
* \param node_base
* \param node_timers
* \return
* \throws std::invalid argument if either node_base or node_timers
* are null
*/
template<typename DurationRepT, typename DurationT, typename CallbackT>
typename rclcpp::WallTimer<CallbackT>::SharedPtr
create_wall_timer(
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group,
node_interfaces::NodeBaseInterface * node_base,
node_interfaces::NodeTimersInterface * node_timers)
{
if (node_base == nullptr) {
throw std::invalid_argument{"input node_base cannot be null"};
}
if (node_timers == nullptr) {
throw std::invalid_argument{"input node_timers cannot be null"};
}
auto timer = rclcpp::WallTimer<CallbackT>::make_shared(
std::chrono::duration_cast<std::chrono::nanoseconds>(period),
std::move(callback),
node_base->get_context());
node_timers->add_timer(timer, group);
return timer;
}
} // namespace rclcpp
#endif // RCLCPP__CREATE_TIMER_HPP_

View File

@@ -42,7 +42,6 @@ resolve_enable_topic_statistics(const OptionsT & options, const NodeBaseT & node
break;
default:
throw std::runtime_error("Unrecognized EnableTopicStatistics value");
break;
}
return topic_stats_enabled;

View File

@@ -26,11 +26,22 @@ namespace rclcpp
class RCLCPP_PUBLIC Duration
{
public:
/// Duration constructor.
/**
* Initializes the time values for seconds and nanoseconds individually.
* Large values for nsecs are wrapped automatically with the remainder added to secs.
* Both inputs must be integers.
* Seconds can be negative.
*
* \param seconds time in seconds
* \param nanoseconds time in nanoseconds
*/
Duration(int32_t seconds, uint32_t nanoseconds);
// This constructor matches any numeric value - ints or floats
// This constructor matches any numeric value - ints or floats.
explicit Duration(rcl_duration_value_t nanoseconds);
// This constructor matches std::chrono::nanoseconds.
explicit Duration(std::chrono::nanoseconds nanoseconds);
// This constructor matches any std::chrono value other than nanoseconds
@@ -44,6 +55,10 @@ public:
// cppcheck-suppress noExplicitConstructor
Duration(const builtin_interfaces::msg::Duration & duration_msg); // NOLINT(runtime/explicit)
/// Time constructor
/**
* \param duration rcl_duration_t structure to copy.
*/
explicit Duration(const rcl_duration_t & duration);
Duration(const Duration & rhs);
@@ -80,6 +95,10 @@ public:
Duration
operator-(const rclcpp::Duration & rhs) const;
/// Get the maximum representable value.
/**
* \return the maximum representable value
*/
static
Duration
max();
@@ -87,19 +106,27 @@ public:
Duration
operator*(double scale) const;
/// Get duration in nanosecods
/**
* \return the duration in nanoseconds as a rcl_duration_value_t.
*/
rcl_duration_value_t
nanoseconds() const;
/// \return the duration in seconds as a floating point number.
/// \warning Depending on sizeof(double) there could be significant precision loss.
/// When an exact time is required use nanoseconds() instead.
/// Get duration in seconds
/**
* \warning Depending on sizeof(double) there could be significant precision loss.
* When an exact time is required use nanoseconds() instead.
* \return the duration in seconds as a floating point number.
*/
double
seconds() const;
// Create a duration object from a floating point number representing seconds
/// Create a duration object from a floating point number representing seconds
static Duration
from_seconds(double seconds);
/// Convert Duration into a std::chrono::Duration.
template<class DurationT>
DurationT
to_chrono() const
@@ -107,6 +134,7 @@ public:
return std::chrono::duration_cast<DurationT>(std::chrono::nanoseconds(this->nanoseconds()));
}
/// Convert Duration into rmw_time_t.
rmw_time_t
to_rmw_time() const;

View File

@@ -29,241 +29,91 @@
#include "rcl/guard_condition.h"
#include "rcl/wait.h"
#include "rclcpp/callback_group.hpp"
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/executor_options.hpp"
#include "rclcpp/executor_policies/timer_favoring_priority_queue.hpp"
#include "rclcpp/future_return_code.hpp"
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/memory_strategies.hpp"
#include "rclcpp/memory_strategy.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/wait_set.hpp"
namespace rclcpp
{
/// Base class for Executor providing the common interface for adding items, spinning, etc.
class ExecutorBase
// Forward declaration is used in convenience method signature.
class Node;
/// Coordinate the order and timing of available communication tasks.
/**
* Executor provides spin functions (including spin_node_once and spin_some).
* It coordinates the nodes and callback groups by looking for available work and completing it,
* based on the threading or concurrency scheme provided by the subclass implementation.
* An example of available work is executing a subscription callback, or a timer callback.
* The executor structure allows for a decoupling of the communication graph and the execution
* model.
* See SingleThreadedExecutor and MultiThreadedExecutor for examples of execution paradigms.
*/
class Executor
{
public:
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(ExecutorBase)
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(Executor)
/// Default constructor.
/**
* \param[in] options Options for the executor.
* \param[in] options Options used to configure the executor.
*/
RCLCPP_PUBLIC
explicit ExecutorBase(const ExecutorOptions & options = ExecutorOptions());
explicit Executor(const rclcpp::ExecutorOptions & options = rclcpp::ExecutorOptions());
/// Default destructor.
RCLCPP_PUBLIC
virtual ~ExecutorBase();
virtual ~Executor();
/// Execution loop which waits for work, executes work, and repeats until canceled.
/**
* This will block, continuing to wait for work and then execute it, until
* canceled, either by the cancel() method or by the associated context being
* shutdown, either explicitly or due to a SIGINT (perhaps due to ctrl-c).
*/
virtual
void
/// Do work periodically as it becomes available to us. Blocking call, may block indefinitely.
// It is up to the implementation of Executor to implement spin.
virtual void
spin() = 0;
/// Add all of a node's callback groups to the executor.
/// Add a node to the executor.
/**
* Add all of the callback groups of a node to this executor.
*
* If any callback groups are associated with another executor, this method
* will throw a std::runtime_error.
*
* It will also trigger the interrupt guard condition which will cause the
* executor to wake up and consider the changes, then go back to waiting.
* Unless the notify parameter is passed false, in which case it will not
* interrupt the executor, and the changes may not be considered immediately.
*
* \param[in] node_ptr Shared pointer to the node which will have callback groups added.
* \param[in] notify If true, notfiy the executor of changes, otherwise do not.
* \throws std::runtime_error if any callback groups are associated with another executor.
*/
template<class NodeT>
void
add_node(const std::shared_ptr<NodeT> & node_ptr, bool notify = true)
{
this->add_node(
node_ptr->get_node_base_interface(),
notify,
false // raise on encountering already associated callback groups
);
}
/// Overload that takes the NodeBaseInterface directly.
template<class NodeT>
void
add_node(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr,
bool notify = true)
{
this->add_node(
node_ptr,
notify,
false // raise on encountering already associated callback groups
);
}
/// Add all unassociated callback groups of the given node to this executor.
/**
* Same as add_node(), but instead of throwing if a callback group is already
* associated with another exector (already added to it) it will just ignore
* it rather than throwing.
*
* \param[in] node_ptr Shared pointer to the node which will have callback groups added.
* \param[in] notify If true, notfiy the executor of changes, otherwise do not.
*/
template<class NodeT>
void
add_unassociated_callback_groups_from_node(
const std::shared_ptr<NodeT> & node_ptr,
bool notify = true)
{
this->add_node(
node_ptr->get_node_base_interface(),
notify,
true // ignore already associated callback groups
);
}
/// Overload that takes the NodeBaseInterface directly.
template<class NodeT>
void
add_unassociated_callback_groups_from_node(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr,
bool notify = true)
{
this->add_node(
node_ptr,
notify,
true // ignore already associated callback groups
);
}
/// Remove all of a node's callback groups from the executor.
/**
* Remove all of the callback groups of a node from this executor.
*
* It will also trigger the interrupt guard condition which will cause the
* executor to wake up and consider the changes, then go back to waiting.
* Unless the notify parameter is passed false, in which case it will not
* interrupt the executor, and the changes may not be considered immediately.
*
* \param[in] node Node which will have callback groups removed.
* \param[in] notify If true, notfiy the executor of changes, otherwise do not.
*/
template<class NodeT>
void
remove_node(const NodeT & node, bool notify = true)
{
this->remove_node(*node.get_node_base_interface(), notify);
}
/// Overload that takes a shared pointer to the node.
/**
* This is kept for backwards compatibility from when executors shared
* ownership of Nodes.
*/
template<class NodeT>
void
remove_node(const std::shared_ptr<NodeT> & node_ptr, bool notify = true)
{
this->remove_node(*node_ptr->get_node_base_interface(), notify);
}
/// Placeholder used to indicate that a method overload should not notify the executor.
struct DoNotNotify {};
/// Add a callback group to this executor.
/**
* If the given callback group is already associated with another executor,
* this method will throw a std::runtime_error.
*
* This overload of add_callback_group() will notify the executor so it will
* wake up if waiting and consider the changes.
*
* Weak ownership of the callback group is kept by the executor all of the
* time, but while waiting the weak ownership is periodically elevated to
* shared ownership.
* Therefore, if you let the callback group shared pointer go out of scope
* then it will stay in scope until this executor is done using it, at which
* point the callback group will be destructed and automatically removed from
* this executor in the next pass.
*
* \param[in] callback_group_ptr The callback group to be added.
* \throws std::runtime_error if the callback group is associated with another
* executor already.
* \throws std::invalid_argument if the callback group pointer is nullptr.
* An executor can have zero or more nodes which provide work during `spin` functions.
* \param[in] node_ptr Shared pointer to the node to be added.
* \param[in] notify True to trigger the interrupt guard condition during this function. If
* the executor is blocked at the rmw layer while waiting for work and it is notified that a new
* node was added, it will wake up.
*/
RCLCPP_PUBLIC
virtual
void
add_callback_group(rclcpp::CallbackGroup::SharedPtr callback_group_ptr) = 0;
virtual void
add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify = true);
/// Add a callback group to this executor without notifying the executor.
/// Convenience function which takes Node and forwards NodeBaseInterface.
RCLCPP_PUBLIC
virtual void
add_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true);
/// Remove a node from the executor.
/**
* The same as the other overload of add_callback_group(), except it does not
* notify the executor, so it will not wake up and these changes may not be
* considered immediately.
*
* Note, a bool with a default value would be preferable for controlling the
* notify behavior, and we're using it in the add/remove node above, but
* in order to keep this function virtual, and to avoid using default values
* in conjunction with virtual methods, we use an overload instead, in the
* spirit of std::nothrow_t, e.g.:
* https://en.cppreference.com/w/cpp/memory/new/nothrow
* \param[in] node_ptr Shared pointer to the node to remove.
* \param[in] notify True to trigger the interrupt guard condition and wake up the executor.
* This is useful if the last node was removed from the executor while the executor was blocked
* waiting for work in another thread, because otherwise the executor would never be notified.
*/
RCLCPP_PUBLIC
virtual
void
add_callback_group(rclcpp::CallbackGroup::SharedPtr callback_group_ptr, DoNotNotify) = 0;
virtual void
remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify = true);
/// Remove a callback group from this executor.
/**
* If the given callback group is not associated with this executor, this
* method will throw a std::runtime_error.
*
* This overload of add_callback_group() will notify the executor so it will
* wake up if waiting and consider the changes.
*
* \param[in] callback_group The callback group to be removed.
* \throws std::runtime_error if the callback group is not associated with
* this executor.
* \throws std::invalid_argument if the callback group pointer is nullptr.
*/
/// Convenience function which takes Node and forwards NodeBaseInterface.
RCLCPP_PUBLIC
virtual
void
remove_callback_group(const rclcpp::CallbackGroup & callback_group) = 0;
/// Remove a callback group from this executor without notifying the executor.
/**
* The same as the other overload of remove_callback_group(), except it does not
* notify the executor, so it will not wake up and these changes may not be
* considered immediately.
*
* See add_callback_group() for a note about the use of DoNotNotify.
*/
RCLCPP_PUBLIC
virtual
void
remove_callback_group(const rclcpp::CallbackGroup & callback_group, DoNotNotify) = 0;
virtual void
remove_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true);
/// Add a node to executor, execute the next available unit of work, and remove the node.
/**
* \param[in] node Shared pointer to the node to add.
* \param[in] timeout How long to wait for work to become available.
* Negative values cause spin_node_once to block indefinitely (the default
* behavior).
* A timeout of 0 causes this function to be non-blocking.
* \param[in] timeout How long to wait for work to become available. Negative values cause
* spin_node_once to block indefinitely (the default behavior). A timeout of 0 causes this
* function to be non-blocking.
*/
template<typename RepT = int64_t, typename T = std::milli>
void
@@ -278,7 +128,7 @@ public:
}
/// Convenience function which takes Node and forwards NodeBaseInterface.
template<typename NodeT, typename RepT = int64_t, typename T = std::milli>
template<typename NodeT = rclcpp::Node, typename RepT = int64_t, typename T = std::milli>
void
spin_node_once(
std::shared_ptr<NodeT> node,
@@ -292,14 +142,16 @@ public:
/// Add a node, complete all immediately available work, and remove the node.
/**
* \param[in] node Shared pointer to the node to spin some.
* \param[in] node Shared pointer to the node to add.
*/
template<class NodeT>
RCLCPP_PUBLIC
void
spin_node_some(const std::shared_ptr<NodeT> & node)
{
this->spin_node_some(node->get_node_base_interface());
}
spin_node_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node);
/// Convenience function which takes Node and forwards NodeBaseInterface.
RCLCPP_PUBLIC
void
spin_node_some(std::shared_ptr<rclcpp::Node> node);
/// Complete all available queued work without blocking.
/**
@@ -313,14 +165,12 @@ public:
* been exceeded.
*/
RCLCPP_PUBLIC
virtual
void
spin_some(std::chrono::nanoseconds max_duration = std::chrono::nanoseconds(0)) = 0;
virtual void
spin_some(std::chrono::nanoseconds max_duration = std::chrono::nanoseconds(0));
RCLCPP_PUBLIC
virtual
void
spin_once(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1)) = 0;
virtual void
spin_once(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
/// Spin (blocking) until the future is complete, it times out waiting, or rclcpp is interrupted.
/**
@@ -382,182 +232,103 @@ public:
}
/// Cancel any running spin* function, causing it to return.
/* This function can be called asynchonously from any thread. */
RCLCPP_PUBLIC
void
cancel();
/// Support dynamic switching of the memory strategy.
/**
* This function can be called asynchronously from any thread.
* Switching the memory strategy while the executor is spinning in another threading could have
* unintended consequences.
* \param[in] memory_strategy Shared pointer to the memory strategy to set.
*/
RCLCPP_PUBLIC
virtual
void
cancel() = 0;
set_memory_strategy(memory_strategy::MemoryStrategy::SharedPtr memory_strategy);
protected:
/// Implementation of add_node().
/**
* \param[in] node_ptr The node which will have its callback groups added.
* \param[in] notify If true, the executor is interrupted to consider the
* changes, otherwise it is not interrupted.
* \param[in] ignore_associated_callback_groups If true, then when a callback
* group which is already been added to another executor is encountered
* it will be ignored, if false then std::runtime_error is thrown instead.
* \throws std::runtime_error if ignore_associated_callback_groups is false
* and a callback group which is already associated with another executor
* is encountered.
* \throws std::invalid_argument if node_ptr is nullptr.
*/
RCLCPP_PUBLIC
virtual
void
add_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
bool notify,
bool ignore_associated_callback_groups) = 0;
RCLCPP_PUBLIC
virtual
void
remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify) = 0;
RCLCPP_PUBLIC
void
spin_node_once_nanoseconds(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
virtual
void
spin_node_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node);
/// Find the next available executable and do the work associated with it.
/** \param[in] any_exec Union structure that can hold any executable type (timer, subscription,
* service, client).
*/
RCLCPP_PUBLIC
void
execute_any_executable(rclcpp::AnyExecutable & any_exec);
execute_any_executable(AnyExecutable & any_exec);
RCLCPP_PUBLIC
static
void
static void
execute_subscription(
rclcpp::SubscriptionBase::SharedPtr subscription);
RCLCPP_PUBLIC
static
void
static void
execute_timer(rclcpp::TimerBase::SharedPtr timer);
RCLCPP_PUBLIC
static
void
static void
execute_service(rclcpp::ServiceBase::SharedPtr service);
RCLCPP_PUBLIC
static
void
static void
execute_client(rclcpp::ClientBase::SharedPtr client);
RCLCPP_PUBLIC
void
wait_for_work(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
get_node_by_group(rclcpp::CallbackGroup::SharedPtr group);
RCLCPP_PUBLIC
rclcpp::CallbackGroup::SharedPtr
get_group_by_timer(rclcpp::TimerBase::SharedPtr timer);
RCLCPP_PUBLIC
bool
get_next_ready_executable(rclcpp::AnyExecutable & any_executable);
get_next_ready_executable(AnyExecutable & any_executable);
RCLCPP_PUBLIC
bool
get_next_executable(
rclcpp::AnyExecutable & any_executable,
AnyExecutable & any_executable,
std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
RCLCPP_DISABLE_COPY(ExecutorBase)
/// Spinning state, used to prevent multi threaded calls to spin and to cancel blocking spins.
std::atomic_bool spinning;
/// Guard condition for signaling the rmw layer to wake up for special events.
rclcpp::GuardCondition interrupt_guard_condition_;
// rcl_guard_condition_t interrupt_guard_condition_ = rcl_get_zero_initialized_guard_condition();
rcl_guard_condition_t interrupt_guard_condition_ = rcl_get_zero_initialized_guard_condition();
// /// Wait set for managing entities that the rmw layer waits on.
// rcl_wait_set_t wait_set_ = rcl_get_zero_initialized_wait_set();
/// Wait set for managing entities that the rmw layer waits on.
rcl_wait_set_t wait_set_ = rcl_get_zero_initialized_wait_set();
// // Mutex to protect the subsequent memory_strategy_.
// std::mutex memory_strategy_mutex_;
// Mutex to protect the subsequent memory_strategy_.
std::mutex memory_strategy_mutex_;
// /// The memory strategy: an interface for handling user-defined memory allocation strategies.
// memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;
/// The memory strategy: an interface for handling user-defined memory allocation strategies.
memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;
/// The context associated with this executor.
rclcpp::Context::SharedPtr context_;
std::shared_ptr<rclcpp::Context> context_;
// std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> weak_nodes_;
// std::list<const rcl_guard_condition_t *> guard_conditions_;
std::vector<rclcpp::CallbackGroup::WeakPtr> weak_guard_conditions_;
RCLCPP_DISABLE_COPY(Executor)
std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> weak_nodes_;
std::list<const rcl_guard_condition_t *> guard_conditions_;
};
/// Template class which serves as the foundation of actual executors.
/**
* This class combines the wait set, scheduling policy, and the ExecutorBase
* class, and implements all of the pure virtual functions of ExecutorBase
* making it a concrete class.
*/
template<class WaitSetT, class SchedulingPolicy>
class ExecutorTemplate : public ExecutorBase, public SchedulingPolicy
{
public:
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(ExecutorTemplate)
/// Default constructor.
/**
* \param[in] options Options for the executor.
*/
explicit ExecutorTemplate(const ExecutorOptions & options = ExecutorOptions())
: ExecutorBase(options), SchedulingPolicy(options), WaitSetT(options.context)
{}
/// Default virtual destructor.
RCLCPP_PUBLIC
virtual
~ExecutorTemplate() = default;
protected:
WaitSetT wait_set_;
};
/// Executor concept which waits for work and coordinates execution of user callbacks.
/**
* Executor provides spin functions (including spin_node_once and spin_some).
* It coordinates the nodes and callback groups by looking for available work
* and completing it, based on the threading or concurrency scheme provided by
* the subclass implementation.
* An example of available work is executing a subscription callback, or a
* timer callback.
* The executor structure allows for a decoupling of the communication graph
* and the execution model.
* See SingleThreadedExecutor and MultiThreadedExecutor for examples of
* different execution paradigms.
*
* By default this alias provides a foundation based on specific wait set type
* and a scheduling policy.
* The wait set is expected to be dynamic, i.e. items can be added or removed
* after creation, and thread-safe, i.e. items can be added or removed while
* also waiting concurrently.
*/
using Executor = ExecutorTemplate<
rclcpp::ThreadSafeWaitSet,
rclcpp::executor_policies::TimerFavoringPriorityQueue>;
namespace executor
{
using Executor [[deprecated("use rclcpp::Executor instead")]] = Executor;
using Executor [[deprecated("use rclcpp::Executor instead")]] = rclcpp::Executor;
} // namespace executor
} // namespace rclcpp

View File

@@ -1,4 +1,4 @@
// Copyright 2014 Open Source Robotics Foundation, Inc.
// Copyright 2014-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.
@@ -43,6 +43,14 @@ namespace executor
using ExecutorArgs [[deprecated("use rclcpp::ExecutorOptions instead")]] = ExecutorOptions;
[[deprecated("use rclcpp::ExecutorOptions() instead")]]
inline
rclcpp::ExecutorOptions
create_default_executor_arguments()
{
return rclcpp::ExecutorOptions();
}
} // namespace executor
} // namespace rclcpp

View File

@@ -1,35 +0,0 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__EXECUTOR_POLICIES__SCHEDULING_RESULT_HPP_
#define RCLCPP__EXECUTOR_POLICIES__SCHEDULING_RESULT_HPP_
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace executor_policies
{
/// Represents the directions a SchedulingPolicy can give to an Executor.
enum RCLCPP_PUBLIC SchedulingResult
{
ContinueExecuting, //<! Indicates more work should be done before waiting.
WaitForWork, //<! Indicates that the executor should wait on the wait set again.
};
} // namespace executor_policies
} // namespace rclcpp
#endif // RCLCPP__EXECUTOR_POLICIES__SCHEDULING_RESULT_HPP_

View File

@@ -1,77 +0,0 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__EXECUTOR_POLICIES__TIMER_FAVORING_PRIORITY_QUEUE_HPP_
#define RCLCPP__EXECUTOR_POLICIES__TIMER_FAVORING_PRIORITY_QUEUE_HPP_
#include "rclcpp/any_executable.hpp"
#include "rclcpp/executor_options.hpp"
#include "rclcpp/executor_policies/scheduling_result.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/wait_result.hpp"
namespace rclcpp
{
namespace executor_policies
{
/// A naive scheduling policy which selects Timers first, then Subscriptions and other items.
/**
* Items are executed in the order they were added, favoring Timers, then
* Subscriptions, Service Servers, Service Clients, and finally Waitables.
* All Timers are executed before any Subscriptions, and all Subscriptions
* before any Service Servers, and so on.
*
* User guard conditions are not yet supported by the Executor and so all guard
* condition are used by the executor itself and are handled before this policy
* is consulted.
* Therefore, guard conditions are ignored for the purposes of scheduling.
*
* This is a naive policy, but is the default until a better one is implemented.
*/
class TimerFavoringPriorityQueue
{
public:
explicit TimerFavoringPriorityQueue(const rclcpp::ExecutorOptions &) {}
/// Select which item should next be executed, and indicate if waiting should resume.
/**
* Selects which item to be executed next, assign it to the any_executable, or
* assigning nullptr if no work should be done right now.
*
* This method is called by the executor after waiting on a wait set, in
* order to determine what to execute next based on the result.
*
* Additionally, if returning SchedulingResult::ContinueExecuting then the
* executor will call this function again without waiting on the wait set, or
* if returning SchedulingResult::WaitForWork then the executor will wait on
* the wait set again after executing the selected any_executable, or
* immediately if any_executable was assigned nullptr.
*/
template<class WaitSetT>
rclcpp::executor_policies::SchedulingResult
schedule_next_any_executable(
const WaitResult<WaitSetT> & wait_result,
rclcpp::AnyExecutable & any_executable)
{
// Explicitly ignore guard conditions.
// Check Timers for being ready.
}
};
} // namespace executor_policies
} // namespace rclcpp
#endif // RCLCPP__EXECUTOR_POLICIES__TIMER_FAVORING_PRIORITY_QUEUE_HPP_

View File

@@ -47,6 +47,14 @@ namespace executor
using FutureReturnCode [[deprecated("use rclcpp::FutureReturnCode instead")]] = FutureReturnCode;
[[deprecated("use rclcpp::to_string(const rclcpp::FutureReturnCode &) instead")]]
inline
std::string
to_string(const rclcpp::FutureReturnCode & future_return_code)
{
return rclcpp::to_string(future_return_code);
}
} // namespace executor
} // namespace rclcpp

View File

@@ -42,6 +42,16 @@ public:
RCLCPP_PUBLIC
InitOptions(const InitOptions & other);
/// Return `true` if logging should be initialized when `rclcpp::Context::init` is called.
RCLCPP_PUBLIC
bool
auto_initialize_logging() const;
/// Set flag indicating if logging should be initialized or not.
RCLCPP_PUBLIC
InitOptions &
auto_initialize_logging(bool initialize_logging);
/// Assignment operator.
RCLCPP_PUBLIC
InitOptions &
@@ -62,6 +72,7 @@ protected:
private:
std::unique_ptr<rcl_init_options_t> init_options_;
bool initialize_logging_{true};
};
} // namespace rclcpp

View File

@@ -23,6 +23,7 @@
#include "rclcpp/allocator/allocator_common.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/serialized_message.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rcutils/logging_macros.h"
@@ -46,10 +47,10 @@ public:
using MessageAlloc = typename MessageAllocTraits::allocator_type;
using MessageDeleter = allocator::Deleter<MessageAlloc, MessageT>;
using SerializedMessageAllocTraits = allocator::AllocRebind<rcl_serialized_message_t, Alloc>;
using SerializedMessageAllocTraits = allocator::AllocRebind<rclcpp::SerializedMessage, Alloc>;
using SerializedMessageAlloc = typename SerializedMessageAllocTraits::allocator_type;
using SerializedMessageDeleter =
allocator::Deleter<SerializedMessageAlloc, rcl_serialized_message_t>;
allocator::Deleter<SerializedMessageAlloc, rclcpp::SerializedMessage>;
using BufferAllocTraits = allocator::AllocRebind<char, Alloc>;
using BufferAlloc = typename BufferAllocTraits::allocator_type;
@@ -86,31 +87,12 @@ public:
return std::allocate_shared<MessageT, MessageAlloc>(*message_allocator_.get());
}
virtual std::shared_ptr<rcl_serialized_message_t> borrow_serialized_message(size_t capacity)
virtual std::shared_ptr<rclcpp::SerializedMessage> borrow_serialized_message(size_t capacity)
{
auto msg = new rcl_serialized_message_t;
*msg = rmw_get_zero_initialized_serialized_message();
auto ret = rmw_serialized_message_init(msg, capacity, &rcutils_allocator_);
if (ret != RCL_RET_OK) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
auto serialized_msg = std::shared_ptr<rcl_serialized_message_t>(
msg,
[](rmw_serialized_message_t * msg) {
auto fini_ret = rmw_serialized_message_fini(msg);
delete msg;
if (fini_ret != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"failed to destroy serialized message: %s", rcl_get_error_string().str);
}
});
return serialized_msg;
return std::make_shared<rclcpp::SerializedMessage>(capacity);
}
virtual std::shared_ptr<rcl_serialized_message_t> borrow_serialized_message()
virtual std::shared_ptr<rclcpp::SerializedMessage> borrow_serialized_message()
{
return borrow_serialized_message(default_buffer_capacity_);
}
@@ -127,7 +109,8 @@ public:
msg.reset();
}
virtual void return_serialized_message(std::shared_ptr<rcl_serialized_message_t> & serialized_msg)
virtual void return_serialized_message(
std::shared_ptr<rclcpp::SerializedMessage> & serialized_msg)
{
serialized_msg.reset();
}

View File

@@ -186,8 +186,8 @@ public:
/// Create and return a Subscription.
/**
* \param[in] topic_name The topic to subscribe on.
* \param[in] qos QoS profile for Subcription.
* \param[in] callback The user-defined callback function to receive a message
* \param[in] qos_history_depth The depth of the subscription's incoming message queue.
* \param[in] options Additional options for the creation of the Subscription.
* \param[in] msg_mem_strat The message memory strategy to use for allocating messages.
* \return Shared pointer to the created subscription.
@@ -229,7 +229,13 @@ public:
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/* Create and return a Client. */
/// Create and return a Client.
/**
* \param[in] service_name The topic to service on.
* \param[in] rmw_qos_profile_t Quality of service profile for client.
* \param[in] group Callback group to call the service.
* \return Shared pointer to the created client.
*/
template<typename ServiceT>
typename rclcpp::Client<ServiceT>::SharedPtr
create_client(
@@ -237,7 +243,14 @@ public:
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/* Create and return a Service. */
/// Create and return a Service.
/**
* \param[in] service_name The topic to service on.
* \param[in] callback User-defined callback function.
* \param[in] rmw_qos_profile_t Quality of service profile for client.
* \param[in] group Callback group to call the service.
* \return Shared pointer to the created service.
*/
template<typename ServiceT, typename CallbackT>
typename rclcpp::Service<ServiceT>::SharedPtr
create_service(
@@ -1111,19 +1124,6 @@ public:
const rclcpp::NodeOptions &
get_node_options() const;
/// Manually assert that this Node is alive (for RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_NODE).
/**
* If the rmw Liveliness policy is set to RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_NODE, the creator
* of this node may manually call `assert_liveliness` at some point in time to signal to the rest
* of the system that this Node is still alive.
*
* \return `true` if the liveliness was asserted successfully, otherwise `false`
*/
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
bool
assert_liveliness() const;
protected:
/// Construct a sub-node, which will extend the namespace of all entities created with it.
/**

View File

@@ -19,6 +19,7 @@
#include <rmw/rmw.h>
#include <algorithm>
#include <chrono>
#include <cstdlib>
#include <iostream>
#include <limits>
@@ -37,10 +38,12 @@
#include "rclcpp/create_client.hpp"
#include "rclcpp/create_publisher.hpp"
#include "rclcpp/create_service.hpp"
#include "rclcpp/create_timer.hpp"
#include "rclcpp/create_subscription.hpp"
#include "rclcpp/detail/resolve_enable_topic_statistics.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/timer.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -108,12 +111,12 @@ Node::create_wall_timer(
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group)
{
auto timer = rclcpp::WallTimer<CallbackT>::make_shared(
std::chrono::duration_cast<std::chrono::nanoseconds>(period),
return rclcpp::create_wall_timer(
period,
std::move(callback),
this->node_base_->get_context());
node_timers_->add_timer(timer, group);
return timer;
group,
this->node_base_.get(),
this->node_timers_.get());
}
template<typename ServiceT>

View File

@@ -1,149 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__NODE_INTERFACES__GET_NODE_BASE_INTERFACE_HPP_
#define RCLCPP__NODE_INTERFACES__GET_NODE_BASE_INTERFACE_HPP_
#include <memory>
#include <utility>
#include <type_traits>
#include "rclcpp/node_interfaces/node_base_interface.hpp"
/// This header provides the get_node_base_interface() template function.
/**
* This function is useful for getting the NodeBaseInterface pointer from
* various kinds of Node-like classes.
*
* It's able to get the NodeBaseInterface pointer so long as the class
* has a method called ``get_node_base_interface()`` which returns
* either a pointer (const or not) to a NodeBaseInterface or a
* std::shared_ptr to a NodeBaseInterface.
*/
namespace rclcpp
{
namespace node_interfaces
{
namespace detail
{
// This is a meta-programming checker for if a given Node-like object has a
// getter called get_node_base_interface() which returns various types,
// e.g. const pointer or a shared pointer.
template<typename NodeType, typename ReturnType>
struct has_get_node_base_interface
{
private:
template<typename T>
static constexpr
auto
check(T *)->typename std::is_same<
decltype(std::declval<T>().get_node_base_interface()),
ReturnType
>::type;
template<typename>
static constexpr
std::false_type
check(...);
public:
using type = decltype(check<NodeType>(nullptr));
static constexpr bool value = type::value;
};
// If NodeType is a pointer to NodeBaseInterface already (just normal function overload).
inline
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface_from_pointer(rclcpp::node_interfaces::NodeBaseInterface * pointer)
{
return pointer;
}
// If NodeType has a method called get_node_base_interface() which returns a shared pointer.
template<
typename NodeType,
typename std::enable_if<has_get_node_base_interface<
typename std::remove_pointer<NodeType>::type,
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface>
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface_from_pointer(NodeType node_pointer)
{
return node_pointer->get_node_base_interface().get();
}
// If NodeType has a method called get_node_base_interface() which returns a pointer.
template<
typename NodeType,
typename std::enable_if<has_get_node_base_interface<
typename std::remove_pointer<NodeType>::type,
rclcpp::node_interfaces::NodeBaseInterface *
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface_from_pointer(NodeType node_pointer)
{
return node_pointer->get_node_base_interface();
}
// Forward shared_ptr's to const node pointer signatures.
template<
typename NodeType,
typename std::enable_if<std::is_same<
NodeType,
typename std::shared_ptr<typename std::remove_pointer<NodeType>::type::element_type> *
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface_from_pointer(NodeType node_shared_pointer)
{
return get_node_base_interface_from_pointer(node_shared_pointer->get());
}
} // namespace detail
/// Get the NodeBaseInterface as a pointer from a pointer to a "Node like" object.
template<
typename NodeType,
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface(NodeType node_pointer)
{
// Forward pointers to detail implmentation directly.
return detail::get_node_base_interface_from_pointer(node_pointer);
}
/// Get the NodeBaseInterface as a pointer from a "Node like" object.
template<
typename NodeType,
typename std::enable_if<
!std::is_pointer<typename std::remove_reference<NodeType>::type>::value, int
>::type = 0
>
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface(NodeType && node_reference)
{
// Forward references to detail implmentation as a pointer.
return detail::get_node_base_interface_from_pointer(&node_reference);
}
} // namespace node_interfaces
} // namespace rclcpp
#endif // RCLCPP__NODE_INTERFACES__GET_NODE_BASE_INTERFACE_HPP_

View File

@@ -1,149 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__NODE_INTERFACES__GET_NODE_TIMERS_INTERFACE_HPP_
#define RCLCPP__NODE_INTERFACES__GET_NODE_TIMERS_INTERFACE_HPP_
#include <memory>
#include <utility>
#include <type_traits>
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
/// This header provides the get_node_timers_interface() template function.
/**
* This function is useful for getting the NodeTimersInterface pointer from
* various kinds of Node-like classes.
*
* It's able to get the NodeTimersInterface pointer so long as the class
* has a method called ``get_node_timers_interface()`` which returns
* either a pointer (const or not) to a NodeTimersInterface or a
* std::shared_ptr to a NodeTimersInterface.
*/
namespace rclcpp
{
namespace node_interfaces
{
namespace detail
{
// This is a meta-programming checker for if a given Node-like object has a
// getter called get_node_timers_interface() which returns various types,
// e.g. const pointer or a shared pointer.
template<typename NodeType, typename ReturnType>
struct has_get_node_timers_interface
{
private:
template<typename T>
static constexpr
auto
check(T *)->typename std::is_same<
decltype(std::declval<T>().get_node_timers_interface()),
ReturnType
>::type;
template<typename>
static constexpr
std::false_type
check(...);
public:
using type = decltype(check<NodeType>(nullptr));
static constexpr bool value = type::value;
};
// If NodeType is a pointer to NodeTimersInterface already (just normal function overload).
inline
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface_from_pointer(rclcpp::node_interfaces::NodeTimersInterface * pointer)
{
return pointer;
}
// If NodeType has a method called get_node_timers_interface() which returns a shared pointer.
template<
typename NodeType,
typename std::enable_if<has_get_node_timers_interface<
typename std::remove_pointer<NodeType>::type,
std::shared_ptr<rclcpp::node_interfaces::NodeTimersInterface>
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface_from_pointer(NodeType node_pointer)
{
return node_pointer->get_node_timers_interface().get();
}
// If NodeType has a method called get_node_timers_interface() which returns a pointer.
template<
typename NodeType,
typename std::enable_if<has_get_node_timers_interface<
typename std::remove_pointer<NodeType>::type,
rclcpp::node_interfaces::NodeTimersInterface *
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface_from_pointer(NodeType node_pointer)
{
return node_pointer->get_node_timers_interface();
}
// Forward shared_ptr's to const node pointer signatures.
template<
typename NodeType,
typename std::enable_if<std::is_same<
NodeType,
typename std::shared_ptr<typename std::remove_pointer<NodeType>::type::element_type> *
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface_from_pointer(NodeType node_shared_pointer)
{
return get_node_timers_interface_from_pointer(node_shared_pointer->get());
}
} // namespace detail
/// Get the NodeTimersInterface as a pointer from a pointer to a "Node like" object.
template<
typename NodeType,
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface(NodeType node_pointer)
{
// Forward pointers to detail implmentation directly.
return detail::get_node_timers_interface_from_pointer(node_pointer);
}
/// Get the NodeTimersInterface as a pointer from a "Node like" object.
template<
typename NodeType,
typename std::enable_if<
!std::is_pointer<typename std::remove_reference<NodeType>::type>::value, int
>::type = 0
>
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface(NodeType && node_reference)
{
// Forward references to detail implmentation as a pointer.
return detail::get_node_timers_interface_from_pointer(&node_reference);
}
} // namespace node_interfaces
} // namespace rclcpp
#endif // RCLCPP__NODE_INTERFACES__GET_NODE_TIMERS_INTERFACE_HPP_

View File

@@ -1,149 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__NODE_INTERFACES__GET_NODE_TOPICS_INTERFACE_HPP_
#define RCLCPP__NODE_INTERFACES__GET_NODE_TOPICS_INTERFACE_HPP_
#include <memory>
#include <utility>
#include <type_traits>
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
/// This header provides the get_node_topics_interface() template function.
/**
* This function is useful for getting the NodeTopicsInterface pointer from
* various kinds of Node-like classes.
*
* It's able to get the NodeTopicsInterface pointer so long as the class
* has a method called ``get_node_topics_interface()`` which returns
* either a pointer (const or not) to a NodeTopicsInterface or a
* std::shared_ptr to a NodeTopicsInterface.
*/
namespace rclcpp
{
namespace node_interfaces
{
namespace detail
{
// This is a meta-programming checker for if a given Node-like object has a
// getter called get_node_topics_interface() which returns various types,
// e.g. const pointer or a shared pointer.
template<typename NodeType, typename ReturnType>
struct has_get_node_topics_interface
{
private:
template<typename T>
static constexpr
auto
check(T *)->typename std::is_same<
decltype(std::declval<T>().get_node_topics_interface()),
ReturnType
>::type;
template<typename>
static constexpr
std::false_type
check(...);
public:
using type = decltype(check<NodeType>(nullptr));
static constexpr bool value = type::value;
};
// If NodeType is a pointer to NodeTopicsInterface already (just normal function overload).
inline
rclcpp::node_interfaces::NodeTopicsInterface *
get_node_topics_interface_from_pointer(rclcpp::node_interfaces::NodeTopicsInterface * pointer)
{
return pointer;
}
// If NodeType has a method called get_node_topics_interface() which returns a shared pointer.
template<
typename NodeType,
typename std::enable_if<has_get_node_topics_interface<
typename std::remove_pointer<NodeType>::type,
std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface>
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTopicsInterface *
get_node_topics_interface_from_pointer(NodeType node_pointer)
{
return node_pointer->get_node_topics_interface().get();
}
// If NodeType has a method called get_node_topics_interface() which returns a pointer.
template<
typename NodeType,
typename std::enable_if<has_get_node_topics_interface<
typename std::remove_pointer<NodeType>::type,
rclcpp::node_interfaces::NodeTopicsInterface *
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTopicsInterface *
get_node_topics_interface_from_pointer(NodeType node_pointer)
{
return node_pointer->get_node_topics_interface();
}
// Forward shared_ptr's to const node pointer signatures.
template<
typename NodeType,
typename std::enable_if<std::is_same<
NodeType,
typename std::shared_ptr<typename std::remove_pointer<NodeType>::type::element_type> *
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTopicsInterface *
get_node_topics_interface_from_pointer(NodeType node_shared_pointer)
{
return get_node_topics_interface_from_pointer(node_shared_pointer->get());
}
} // namespace detail
/// Get the NodeTopicsInterface as a pointer from a pointer to a "Node like" object.
template<
typename NodeType,
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTopicsInterface *
get_node_topics_interface(NodeType node_pointer)
{
// Forward pointers to detail implmentation directly.
return detail::get_node_topics_interface_from_pointer(node_pointer);
}
/// Get the NodeTopicsInterface as a pointer from a "Node like" object.
template<
typename NodeType,
typename std::enable_if<
!std::is_pointer<typename std::remove_reference<NodeType>::type>::value, int
>::type = 0
>
rclcpp::node_interfaces::NodeTopicsInterface *
get_node_topics_interface(NodeType && node_reference)
{
// Forward references to detail implmentation as a pointer.
return detail::get_node_topics_interface_from_pointer(&node_reference);
}
} // namespace node_interfaces
} // namespace rclcpp
#endif // RCLCPP__NODE_INTERFACES__GET_NODE_TOPICS_INTERFACE_HPP_

View File

@@ -91,11 +91,6 @@ public:
RCLCPP_PUBLIC
bool
assert_liveliness() const override;
RCLCPP_PUBLIC
rclcpp::CallbackGroup::SharedPtr
create_callback_group(rclcpp::CallbackGroupType group_type) override;

View File

@@ -102,12 +102,6 @@ public:
std::shared_ptr<const rcl_node_t>
get_shared_rcl_node_handle() const = 0;
/// Manually assert that this Node is alive (for RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_NODE).
RCLCPP_PUBLIC
virtual
bool
assert_liveliness() const = 0;
/// Create and return a callback group.
RCLCPP_PUBLIC
virtual

View File

@@ -22,6 +22,7 @@
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/publisher.hpp"
#include "rclcpp/publisher_factory.hpp"
@@ -39,7 +40,9 @@ public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeTopicsInterface)
RCLCPP_PUBLIC
explicit NodeTopics(rclcpp::node_interfaces::NodeBaseInterface * node_base);
NodeTopics(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
rclcpp::node_interfaces::NodeTimersInterface * node_timers);
RCLCPP_PUBLIC
~NodeTopics() override;
@@ -74,10 +77,15 @@ public:
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface() const override;
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface() const override;
private:
RCLCPP_DISABLE_COPY(NodeTopics)
rclcpp::node_interfaces::NodeBaseInterface * node_base_;
rclcpp::node_interfaces::NodeTimersInterface * node_timers_;
};
} // namespace node_interfaces

View File

@@ -25,6 +25,7 @@
#include "rclcpp/callback_group.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
#include "rclcpp/publisher.hpp"
#include "rclcpp/publisher_factory.hpp"
#include "rclcpp/subscription.hpp"
@@ -80,6 +81,11 @@ public:
virtual
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface() const = 0;
RCLCPP_PUBLIC
virtual
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface() const = 0;
};
} // namespace node_interfaces

View File

@@ -83,18 +83,22 @@ public:
bool
operator!=(const Parameter & rhs) const;
/// Get the type of the parameter
RCLCPP_PUBLIC
ParameterType
get_type() const;
/// Get the type name of the parameter
RCLCPP_PUBLIC
std::string
get_type_name() const;
/// Get the name of the parameter
RCLCPP_PUBLIC
const std::string &
get_name() const;
/// Get value of parameter as a parameter message.
RCLCPP_PUBLIC
rcl_interfaces::msg::ParameterValue
get_value_message() const;
@@ -105,6 +109,9 @@ public:
get_parameter_value() const;
/// Get value of parameter using rclcpp::ParameterType as template argument.
/**
* \throws rclcpp::exceptions::InvalidParameterTypeException if the type doesn't match
*/
template<ParameterType ParamT>
decltype(auto)
get_value() const
@@ -117,50 +124,89 @@ public:
decltype(auto)
get_value() const;
/// Get value of parameter as boolean.
/**
* \throws rclcpp::ParameterTypeException if the type doesn't match
*/
RCLCPP_PUBLIC
bool
as_bool() const;
/// Get value of parameter as integer.
/**
* \throws rclcpp::ParameterTypeException if the type doesn't match
*/
RCLCPP_PUBLIC
int64_t
as_int() const;
/// Get value of parameter as double.
/**
* \throws rclcpp::ParameterTypeException if the type doesn't match
*/
RCLCPP_PUBLIC
double
as_double() const;
/// Get value of parameter as string.
/**
* \throws rclcpp::ParameterTypeException if the type doesn't match
*/
RCLCPP_PUBLIC
const std::string &
as_string() const;
/// Get value of parameter as byte array (vector<uint8_t>).
/**
* \throws rclcpp::ParameterTypeException if the type doesn't match
*/
RCLCPP_PUBLIC
const std::vector<uint8_t> &
as_byte_array() const;
/// Get value of parameter as bool array (vector<bool>).
/**
* \throws rclcpp::ParameterTypeException if the type doesn't match
*/
RCLCPP_PUBLIC
const std::vector<bool> &
as_bool_array() const;
/// Get value of parameter as integer array (vector<int64_t>).
/**
* \throws rclcpp::ParameterTypeException if the type doesn't match
*/
RCLCPP_PUBLIC
const std::vector<int64_t> &
as_integer_array() const;
/// Get value of parameter as double array (vector<double>).
/**
* \throws rclcpp::ParameterTypeException if the type doesn't match
*/
RCLCPP_PUBLIC
const std::vector<double> &
as_double_array() const;
/// Get value of parameter as string array (vector<std::string>).
/**
* \throws rclcpp::ParameterTypeException if the type doesn't match
*/
RCLCPP_PUBLIC
const std::vector<std::string> &
as_string_array() const;
/// Convert a parameter message in a Parameter class object.
RCLCPP_PUBLIC
static Parameter
from_parameter_msg(const rcl_interfaces::msg::Parameter & parameter);
/// Convert the class in a parameter message.
RCLCPP_PUBLIC
rcl_interfaces::msg::Parameter
to_parameter_msg() const;
/// Get value of parameter as a string.
RCLCPP_PUBLIC
std::string
value_to_string() const;

View File

@@ -59,6 +59,17 @@ public:
RCLCPP_SMART_PTR_DEFINITIONS(Publisher<MessageT, AllocatorT>)
/// Default constructor.
/**
* The constructor for a Publisher is almost never called directly.
* Instead, subscriptions should be instantiated through the function
* rclcpp::create_publisher().
*
* \param[in] node_base NodeBaseInterface pointer that is used in part of the setup.
* \param[in] topic Name of the topic to publish to.
* \param[in] qos QoS profile for Subcription.
* \param[in] options options for the subscription.
*/
Publisher(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const std::string & topic,
@@ -217,6 +228,12 @@ public:
return this->do_serialized_publish(&serialized_msg);
}
void
publish(const SerializedMessage & serialized_msg)
{
return this->do_serialized_publish(&serialized_msg.get_rcl_serialized_message());
}
/// Publish an instance of a LoanedMessage.
/**
* When publishing a loaned message, the memory for this ROS message will be deallocated

View File

@@ -161,6 +161,18 @@ bool operator==(const QoS & left, const QoS & right);
RCLCPP_PUBLIC
bool operator!=(const QoS & left, const QoS & right);
/**
* Sensor Data QoS class
* - History: Keep last,
* - Depth: 5,
* - Reliability: Best effort,
* - Durability: Volatile,
* - Deadline: Default,
* - Lifespan: Default,
* - Liveliness: System default,
* - Liveliness lease duration: default,
* - avoid ros namespace conventions: false
*/
class RCLCPP_PUBLIC SensorDataQoS : public QoS
{
public:
@@ -171,6 +183,18 @@ public:
));
};
/**
* Parameters QoS class
* - History: Keep last,
* - Depth: 1000,
* - Reliability: Reliable,
* - Durability: Volatile,
* - Deadline: Default,
* - Lifespan: Default,
* - Liveliness: System default,
* - Liveliness lease duration: default,
* - Avoid ros namespace conventions: false
*/
class RCLCPP_PUBLIC ParametersQoS : public QoS
{
public:
@@ -181,6 +205,18 @@ public:
));
};
/**
* Services QoS class
* - History: Keep last,
* - Depth: 10,
* - Reliability: Reliable,
* - Durability: Volatile,
* - Deadline: Default,
* - Lifespan: Default,
* - Liveliness: System default,
* - Liveliness lease duration: default,
* - Avoid ros namespace conventions: false
*/
class RCLCPP_PUBLIC ServicesQoS : public QoS
{
public:
@@ -191,6 +227,18 @@ public:
));
};
/**
* Parameter events QoS class
* - History: Keep last,
* - Depth: 1000,
* - Reliability: Reliable,
* - Durability: Volatile,
* - Deadline: Default,
* - Lifespan: Default,
* - Liveliness: System default,
* - Liveliness lease duration: default,
* - Avoid ros namespace conventions: false
*/
class RCLCPP_PUBLIC ParameterEventsQoS : public QoS
{
public:
@@ -201,6 +249,18 @@ public:
));
};
/**
* System defaults QoS class
* - History: System default,
* - Depth: System default,
* - Reliability: System default,
* - Durability: System default,
* - Deadline: Default,
* - Lifespan: Default,
* - Liveliness: System default,
* - Liveliness lease duration: System default,
* - Avoid ros namespace conventions: false
*/
class RCLCPP_PUBLIC SystemDefaultsQoS : public QoS
{
public:

View File

@@ -81,7 +81,7 @@
* - rclcpp/executors/multi_threaded_executor.hpp
* - CallbackGroups (mechanism for enforcing concurrency rules for callbacks):
* - rclcpp::Node::create_callback_group()
* - rclcpp::callback_group::CallbackGroup
* - rclcpp::CallbackGroup
* - rclcpp/callback_group.hpp
*
* Additionally, there are some methods for introspecting the ROS graph:
@@ -128,6 +128,7 @@
* - rclcpp/context.hpp
* - rclcpp/contexts/default_context.hpp
* - Various utilities:
* - rclcpp/duration.hpp
* - rclcpp/function_traits.hpp
* - rclcpp/macros.hpp
* - rclcpp/scope_exit.hpp

View File

@@ -39,10 +39,6 @@ template<typename T>
struct is_serialized_message_class : std::false_type
{};
template<>
struct is_serialized_message_class<rcl_serialized_message_t>: std::true_type
{};
template<>
struct is_serialized_message_class<SerializedMessage>: std::true_type
{};

View File

@@ -98,6 +98,20 @@ public:
*/
size_t capacity() const;
/// Allocate memory in the data buffer
/**
* The data buffer of the underlying rcl_serialized_message_t will be resized.
* This might change the data layout and invalidates all pointers to the data.
*/
void reserve(size_t capacity);
/// Release the underlying rcl_serialized_message_t
/**
* The memory (i.e. the data buffer) of the serialized message will no longer
* be managed by this instance and the memory won't be deallocated on destruction.
*/
rcl_serialized_message_t release_rcl_serialized_message();
private:
rcl_serialized_message_t serialized_message_;
};

View File

@@ -50,14 +50,26 @@ public:
RCLCPP_PUBLIC
virtual ~ServiceBase();
/// Return the name of the service.
/** \return The name of the service. */
RCLCPP_PUBLIC
const char *
get_service_name();
/// Return the rcl_service_t service handle in a std::shared_ptr.
/**
* This handle remains valid after the Service is destroyed.
* The actual rcl service is not finalized until it is out of scope everywhere.
*/
RCLCPP_PUBLIC
std::shared_ptr<rcl_service_t>
get_service_handle();
/// Return the rcl_service_t service handle in a std::shared_ptr.
/**
* This handle remains valid after the Service is destroyed.
* The actual rcl service is not finalized until it is out of scope everywhere.
*/
RCLCPP_PUBLIC
std::shared_ptr<const rcl_service_t>
get_service_handle() const;

View File

@@ -18,6 +18,7 @@
#include <rmw/error_handling.h>
#include <rmw/rmw.h>
#include <chrono>
#include <functional>
#include <iostream>
#include <memory>
@@ -25,7 +26,6 @@
#include <string>
#include <utility>
#include "rcl/error_handling.h"
#include "rcl/subscription.h"
@@ -47,6 +47,7 @@
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/waitable.hpp"
#include "rclcpp/topic_statistics/subscription_topic_statistics.hpp"
#include "tracetools/tracetools.h"
namespace rclcpp
@@ -75,6 +76,8 @@ public:
using MessageDeleter = allocator::Deleter<MessageAllocator, CallbackMessageT>;
using ConstMessageSharedPtr = std::shared_ptr<const CallbackMessageT>;
using MessageUniquePtr = std::unique_ptr<CallbackMessageT, MessageDeleter>;
using SubscriptionTopicStatisticsSharedPtr =
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>>;
RCLCPP_SMART_PTR_DEFINITIONS(Subscription)
@@ -87,9 +90,14 @@ public:
* \param[in] node_base NodeBaseInterface pointer that is used in part of the setup.
* \param[in] type_support_handle rosidl type support struct, for the Message type of the topic.
* \param[in] topic_name Name of the topic to subscribe to.
* \param[in] qos QoS profile for Subcription.
* \param[in] callback User defined callback to call when a message is received.
* \param[in] options options for the subscription.
* \param[in] message_memory_strategy The memory strategy to be used for managing message memory.
* \param[in] subscription_topic_statistics pointer to a topic statistics subcription.
* \throws std::invalid_argument if the QoS is uncompatible with intra-process (if one
* of the following conditions are true: qos_profile.history == RMW_QOS_POLICY_HISTORY_KEEP_ALL,
* qos_profile.depth == 0 or qos_profile.durability != RMW_QOS_POLICY_DURABILITY_VOLATILE).
*/
Subscription(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
@@ -98,7 +106,8 @@ public:
const rclcpp::QoS & qos,
AnySubscriptionCallback<CallbackMessageT, AllocatorT> callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
typename MessageMemoryStrategyT::SharedPtr message_memory_strategy)
typename MessageMemoryStrategyT::SharedPtr message_memory_strategy,
SubscriptionTopicStatisticsSharedPtr subscription_topic_statistics = nullptr)
: SubscriptionBase(
node_base,
type_support_handle,
@@ -180,6 +189,10 @@ public:
this->setup_intra_process(intra_process_subscription_id, ipm);
}
if (subscription_topic_statistics != nullptr) {
this->subscription_topic_statistics_ = std::move(subscription_topic_statistics);
}
TRACEPOINT(
rclcpp_subscription_init,
(const void *)get_subscription_handle().get(),
@@ -242,7 +255,7 @@ public:
return message_memory_strategy_->borrow_message();
}
std::shared_ptr<rcl_serialized_message_t>
std::shared_ptr<rclcpp::SerializedMessage>
create_serialized_message() override
{
return message_memory_strategy_->borrow_serialized_message();
@@ -260,6 +273,13 @@ public:
}
auto typed_message = std::static_pointer_cast<CallbackMessageT>(message);
any_callback_.dispatch(typed_message, message_info);
if (subscription_topic_statistics_) {
const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(
std::chrono::system_clock::now());
const auto time = rclcpp::Time(nanos.time_since_epoch().count());
subscription_topic_statistics_->handle_message(*typed_message, time);
}
}
void
@@ -284,7 +304,7 @@ public:
}
void
return_serialized_message(std::shared_ptr<rcl_serialized_message_t> & message) override
return_serialized_message(std::shared_ptr<rclcpp::SerializedMessage> & message) override
{
message_memory_strategy_->return_serialized_message(message);
}
@@ -307,6 +327,8 @@ private:
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> options_;
typename message_memory_strategy::MessageMemoryStrategy<CallbackMessageT, AllocatorT>::SharedPtr
message_memory_strategy_;
/// Component which computes and publishes topic statistics for this subscriber
SubscriptionTopicStatisticsSharedPtr subscription_topic_statistics_{nullptr};
};
} // namespace rclcpp

View File

@@ -33,6 +33,7 @@
#include "rclcpp/message_info.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/serialized_message.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -151,7 +152,7 @@ public:
*/
RCLCPP_PUBLIC
bool
take_serialized(rcl_serialized_message_t & message_out, rclcpp::MessageInfo & message_info_out);
take_serialized(rclcpp::SerializedMessage & message_out, rclcpp::MessageInfo & message_info_out);
/// Borrow a new message.
/** \return Shared pointer to the fresh message. */
@@ -164,7 +165,7 @@ public:
/** \return Shared pointer to a rcl_message_serialized_t. */
RCLCPP_PUBLIC
virtual
std::shared_ptr<rcl_serialized_message_t>
std::shared_ptr<rclcpp::SerializedMessage>
create_serialized_message() = 0;
/// Check if we need to handle the message, and execute the callback if we do.
@@ -194,7 +195,7 @@ public:
RCLCPP_PUBLIC
virtual
void
return_serialized_message(std::shared_ptr<rcl_serialized_message_t> & message) = 0;
return_serialized_message(std::shared_ptr<rclcpp::SerializedMessage> & message) = 0;
RCLCPP_PUBLIC
const rosidl_message_type_support_t &

View File

@@ -32,6 +32,7 @@
#include "rclcpp/subscription_options.hpp"
#include "rclcpp/subscription_traits.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/topic_statistics/subscription_topic_statistics.hpp"
namespace rclcpp
{
@@ -78,7 +79,10 @@ SubscriptionFactory
create_subscription_factory(
CallbackT && callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat)
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat,
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>>
subscription_topic_stats = nullptr
)
{
auto allocator = options.get_allocator();
@@ -88,7 +92,7 @@ create_subscription_factory(
SubscriptionFactory factory {
// factory function that creates a MessageT specific SubscriptionT
[options, msg_mem_strat, any_subscription_callback](
[options, msg_mem_strat, any_subscription_callback, subscription_topic_stats](
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const std::string & topic_name,
const rclcpp::QoS & qos
@@ -104,7 +108,8 @@ create_subscription_factory(
qos,
any_subscription_callback,
options,
msg_mem_strat);
msg_mem_strat,
subscription_topic_stats);
// This is used for setting up things like intra process comms which
// require this->shared_from_this() which cannot be called from
// the constructor.

View File

@@ -89,6 +89,10 @@ struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
{}
/// Convert this class, with a rclcpp::QoS, into an rcl_subscription_options_t.
/**
* \param qos QoS profile for subcription.
* \return rcl_subscription_options_t structure based on the rclcpp::QoS
*/
template<typename MessageT>
rcl_subscription_options_t
to_rcl_subscription_options(const rclcpp::QoS & qos) const

View File

@@ -42,15 +42,6 @@ template<typename T>
struct is_serialized_subscription_argument : std::false_type
{};
template<>
struct is_serialized_subscription_argument<rcl_serialized_message_t>: std::true_type
{};
template<>
struct is_serialized_subscription_argument<std::shared_ptr<rcl_serialized_message_t>>
: std::true_type
{};
template<>
struct is_serialized_subscription_argument<SerializedMessage>: std::true_type
{};

View File

@@ -31,26 +31,54 @@ class Clock;
class Time
{
public:
/// Time constructor
/**
* Initializes the time values for seconds and nanoseconds individually.
* Large values for nanoseconds are wrapped automatically with the remainder added to seconds.
* Both inputs must be integers.
*
* \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
*/
RCLCPP_PUBLIC
Time(int32_t seconds, uint32_t nanoseconds, rcl_clock_type_t clock_type = RCL_SYSTEM_TIME);
/// Time constructor
/**
* \param nanoseconds since time epoch
* \param clock_type clock type
*/
RCLCPP_PUBLIC
explicit Time(int64_t nanoseconds = 0, rcl_clock_type_t clock = RCL_SYSTEM_TIME);
/// Copy constructor
RCLCPP_PUBLIC
Time(const Time & rhs);
/// Time constructor
/**
* \param time_msg builtin_interfaces time message to copy
* \param clock_type clock type
*/
RCLCPP_PUBLIC
Time(
const builtin_interfaces::msg::Time & time_msg,
rcl_clock_type_t ros_time = RCL_ROS_TIME);
/// Time constructor
/**
* \param time_point rcl_time_point_t structure to copy
* \param clock_type clock type
*/
RCLCPP_PUBLIC
explicit Time(const rcl_time_point_t & time_point);
/// Time destructor
RCLCPP_PUBLIC
virtual ~Time();
/// Return a builtin_interfaces::msg::Time object based
RCLCPP_PUBLIC
operator builtin_interfaces::msg::Time() const;
@@ -106,21 +134,37 @@ public:
Time &
operator-=(const rclcpp::Duration & rhs);
/// Get the nanoseconds since epoch
/**
* \return the nanoseconds since epoch as a rcl_time_point_value_t structure.
*/
RCLCPP_PUBLIC
rcl_time_point_value_t
nanoseconds() const;
/// Get the maximum representable value.
/**
* \return the maximum representable value
*/
RCLCPP_PUBLIC
static Time
max();
/// \return the seconds since epoch as a floating point number.
/// \warning Depending on sizeof(double) there could be significant precision loss.
/// When an exact time is required use nanoseconds() instead.
/// Get the seconds since epoch
/**
* \warning Depending on sizeof(double) there could be significant precision loss.
* When an exact time is required use nanoseconds() instead.
*
* \return the seconds since epoch as a floating point number.
*/
RCLCPP_PUBLIC
double
seconds() const;
/// Get the clock type
/**
* \return the clock type
*/
RCLCPP_PUBLIC
rcl_clock_type_t
get_clock_type() const;

View File

@@ -35,15 +35,42 @@ class Clock;
class TimeSource
{
public:
/// Constructor
/**
* The node will be attached to the time source.
*
* \param node std::shared pointer to a initialized node
*/
RCLCPP_PUBLIC
explicit TimeSource(rclcpp::Node::SharedPtr node);
/// Empty constructor
/**
* An Empty TimeSource class
*/
RCLCPP_PUBLIC
TimeSource();
/// Attack node to the time source.
/**
* \param node std::shared pointer to a initialized node
*/
RCLCPP_PUBLIC
void attachNode(rclcpp::Node::SharedPtr node);
/// Attack node to the time source.
/**
* If the parameter `use_sim_time` is `true` then the source time is the simulation time,
* otherwise the source time is defined by the system.
*
* \param node_base_interface Node base interface.
* \param node_topics_interface Node topic base interface.
* \param node_graph_interface Node graph interface.
* \param node_services_interface Node service interface.
* \param node_logging_interface Node logging interface.
* \param node_clock_interface Node clock interface.
* \param node_parameters_interface Node parameters interface.
*/
RCLCPP_PUBLIC
void attachNode(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface,
@@ -54,19 +81,22 @@ public:
rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock_interface,
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters_interface);
/// Detach the node from the time source
RCLCPP_PUBLIC
void detachNode();
/// Attach a clock to the time source to be updated
/**
* \throws std::invalid_argument if node is nullptr
* \throws std::invalid_argument the time source must be a RCL_ROS_TIME otherwise throws an exception
*/
RCLCPP_PUBLIC
void attachClock(rclcpp::Clock::SharedPtr clock);
/// Detach a clock to the time source
RCLCPP_PUBLIC
void detachClock(rclcpp::Clock::SharedPtr clock);
/// TimeSource Destructor
RCLCPP_PUBLIC
~TimeSource();

View File

@@ -48,15 +48,26 @@ class TimerBase
public:
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(TimerBase)
/// TimerBase constructor
/**
* \param clock A clock to use for time and sleeping
* \param period The interval at which the timer fires
* \param context node context
*/
RCLCPP_PUBLIC
explicit TimerBase(
Clock::SharedPtr clock,
std::chrono::nanoseconds period,
rclcpp::Context::SharedPtr context);
/// TimerBase destructor
RCLCPP_PUBLIC
~TimerBase();
/// Cancel the timer.
/**
* \throws std::runtime_error if the rcl_timer_cancel returns a failure
*/
RCLCPP_PUBLIC
void
cancel();
@@ -71,10 +82,15 @@ public:
bool
is_canceled();
/// Reset the timer.
/**
* \throws std::runtime_error if the rcl_timer_reset returns a failure
*/
RCLCPP_PUBLIC
void
reset();
/// Call the callback function when the timer signal is emitted.
RCLCPP_PUBLIC
virtual void
execute_callback() = 0;
@@ -209,6 +225,8 @@ public:
callback_(*this);
}
/// Is the clock steady (i.e. is the time between ticks constant?)
/** \return True if the clock used by this timer is steady. */
bool
is_steady() override
{
@@ -233,6 +251,12 @@ class WallTimer : public GenericTimer<FunctorT>
public:
RCLCPP_SMART_PTR_DEFINITIONS(WallTimer)
/// Wall timer constructor
/**
* \param period The interval at which the timer fires
* \param callback The callback function to execute every interval
* \param context node context
*/
WallTimer(
std::chrono::nanoseconds period,
FunctorT && callback,

View File

@@ -23,6 +23,7 @@
#include "libstatistics_collector/collector/generate_statistics_message.hpp"
#include "libstatistics_collector/moving_average_statistics/types.hpp"
#include "libstatistics_collector/topic_statistics_collector/constants.hpp"
#include "libstatistics_collector/topic_statistics_collector/received_message_age.hpp"
#include "libstatistics_collector/topic_statistics_collector/received_message_period.hpp"
#include "rcl/time.h"
@@ -56,6 +57,9 @@ class SubscriptionTopicStatistics
using TopicStatsCollector =
libstatistics_collector::topic_statistics_collector::TopicStatisticsCollector<
CallbackMessageT>;
using ReceivedMessageAge =
libstatistics_collector::topic_statistics_collector::ReceivedMessageAgeCollector<
CallbackMessageT>;
using ReceivedMessagePeriod =
libstatistics_collector::topic_statistics_collector::ReceivedMessagePeriodCollector<
CallbackMessageT>;
@@ -94,6 +98,8 @@ public:
/// Handle a message received by the subscription to collect statistics.
/**
* This method acquires a lock to prevent race conditions to collectors list.
*
* \param received_message the message received by the subscription
* \param now_nanoseconds current time in nanoseconds
*/
@@ -101,6 +107,7 @@ public:
const CallbackMessageT & received_message,
const rclcpp::Time now_nanoseconds) const
{
std::lock_guard<std::mutex> lock(mutex_);
for (const auto & collector : subscriber_statistics_collectors_) {
collector->OnMessageReceived(received_message, now_nanoseconds.nanoseconds());
}
@@ -116,21 +123,32 @@ public:
}
/// Publish a populated MetricsStatisticsMessage.
/**
* This method acquires a lock to prevent race conditions to collectors list.
*/
virtual void publish_message()
{
std::vector<MetricsMessage> msgs;
rclcpp::Time window_end{get_current_nanoseconds_since_epoch()};
for (auto & collector : subscriber_statistics_collectors_) {
const auto collected_stats = collector->GetStatisticsResults();
{
std::lock_guard<std::mutex> lock(mutex_);
for (auto & collector : subscriber_statistics_collectors_) {
const auto collected_stats = collector->GetStatisticsResults();
auto message = libstatistics_collector::collector::GenerateStatisticMessage(
node_name_,
collector->GetMetricName(),
collector->GetMetricUnit(),
window_start_,
window_end,
collected_stats);
publisher_->publish(message);
auto message = libstatistics_collector::collector::GenerateStatisticMessage(
node_name_,
collector->GetMetricName(),
collector->GetMetricUnit(),
window_start_,
window_end,
collected_stats);
msgs.push_back(message);
}
}
for (auto & msg : msgs) {
publisher_->publish(msg);
}
window_start_ = window_end;
}
@@ -138,11 +156,14 @@ public:
protected:
/// Return a vector of all the currently collected data.
/**
* This method acquires a lock to prevent race conditions to collectors list.
*
* \return a vector of all the collected data
*/
std::vector<StatisticData> get_current_collector_data() const
{
std::vector<StatisticData> data;
std::lock_guard<std::mutex> lock(mutex_);
for (const auto & collector : subscriber_statistics_collectors_) {
data.push_back(collector->GetStatisticsResults());
}
@@ -151,23 +172,39 @@ protected:
private:
/// Construct and start all collectors and set window_start_.
/**
* This method acquires a lock to prevent race conditions to collectors list.
*/
void bring_up()
{
auto received_message_age = std::make_unique<ReceivedMessageAge>();
received_message_age->Start();
subscriber_statistics_collectors_.emplace_back(std::move(received_message_age));
auto received_message_period = std::make_unique<ReceivedMessagePeriod>();
received_message_period->Start();
subscriber_statistics_collectors_.emplace_back(std::move(received_message_period));
{
std::lock_guard<std::mutex> lock(mutex_);
subscriber_statistics_collectors_.emplace_back(std::move(received_message_period));
}
window_start_ = rclcpp::Time(get_current_nanoseconds_since_epoch());
}
/// Stop all collectors, clear measurements, stop publishing timer, and reset publisher.
/**
* This method acquires a lock to prevent race conditions to collectors list.
*/
void tear_down()
{
for (auto & collector : subscriber_statistics_collectors_) {
collector->Stop();
}
{
std::lock_guard<std::mutex> lock(mutex_);
for (auto & collector : subscriber_statistics_collectors_) {
collector->Stop();
}
subscriber_statistics_collectors_.clear();
subscriber_statistics_collectors_.clear();
}
if (publisher_timer_) {
publisher_timer_->cancel();
@@ -187,6 +224,8 @@ private:
return std::chrono::duration_cast<std::chrono::nanoseconds>(now.time_since_epoch()).count();
}
/// Mutex to protect the subsequence vectors
mutable std::mutex mutex_;
/// Collection of statistics collectors
std::vector<std::unique_ptr<TopicStatsCollector>> subscriber_statistics_collectors_{};
/// Node name used to generate topic statistics messages to be published

View File

@@ -1,48 +0,0 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__WAIT_SET_ALGORITHMS_HPP_
#define RCLCPP__WAIT_SET_ALGORITHMS_HPP_
#include <algorithm>
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/wait_result.hpp"
namespace rclcpp
{
/// Find next ready entity out of the given sequence from start to last.
template<class InputIt>
InputIt
find_next_ready_wait_set_entity(InputIt start, InputIt last)
{
return std::find_if(start, last, [](const auto & entity) {return nullptr != entity;});
}
/// Find next ready guard condition given a WaitResult.
template<class WaitSetT>
typename WaitSetT::StoragePolicy::GuardConditionsIterable::const_iterator
find_next_ready_guard_condition(
const typename rclcpp::WaitResult<WaitSetT> & wait_result,
typename WaitSetT::StoragePolicy::GuardConditionsIterable::const_iterator start = (
wait_result.get_wait_set()))
{
return
}
} // namespace rclcpp
#endif // RCLCPP__WAIT_SET_ALGORITHMS_HPP_

View File

@@ -1,123 +0,0 @@
// Copyright 2020 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__WAIT_SET_POLICIES__DETAIL__ENTRY_TYPES_HPP_
#define RCLCPP__WAIT_SET_POLICIES__DETAIL__ENTRY_TYPES_HPP_
#include <limits>
#include <memory>
#include "rclcpp/client.hpp"
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/service.hpp"
#include "rclcpp/subscription_base.hpp"
#include "rclcpp/subscription_wait_set_mask.hpp"
#include "rclcpp/timer.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/waitable.hpp"
namespace rclcpp
{
namespace wait_set_policies
{
namespace detail
{
constexpr const size_t not_in_wait_set = (std::numeric_limits<std::size_t>::max)();
/// Templated ownership entries used for storage.
template<class PointerT>
class EntryTemplate : public PointerT
{
public:
size_t rcl_wait_set_index;
constexpr static const size_t not_in_wait_set = not_in_wait_set;
/// Conversion constructor, which is intentionally not marked explicit.
EntryTemplate(
const PointerT & entity_in = nullptr,
size_t rcl_wait_set_index_in = not_in_wait_set) noexcept
: PointerT(entity_in),
rcl_wait_set_index(rcl_wait_set_index_in)
{}
};
/// Templated ownership subscription entries used for storage.
template<class PointerT>
class SubscriptionEntryTemplate : public EntryTemplate<PointerT>
{
public:
rclcpp::SubscriptionWaitSetMask mask;
/// Conversion constructor, which is intentionally not marked explicit.
SubscriptionEntryTemplate(
const PointerT & entity_in = nullptr,
const rclcpp::SubscriptionWaitSetMask & mask_in = {},
size_t rcl_wait_set_index_in = not_in_wait_set) noexcept
: EntryTemplate<PointerT>(entity_in, rcl_wait_set_index_in),
mask(mask_in)
{}
};
/// Templated ownership entries with associated entity used for storage.
template<class PointerT>
class EntryWithAssociatedEntityTemplate : public PointerT
{
public:
std::shared_ptr<void> associated_entity;
/// Conversion constructor, which is intentionally not marked explicit.
EntryWithAssociatedEntityTemplate(
const PointerT & entity_in = nullptr,
const std::shared_ptr<void> & associated_entity_in = nullptr) noexcept
: PointerT(entity_in),
associated_entity(associated_entity_in)
{}
};
/// Shared ownership SubscriptionBase entry for storage.
using SubscriptionEntry = SubscriptionEntryTemplate<std::shared_ptr<rclcpp::SubscriptionBase>>;
/// Weak ownership SubscriptionBase entry for storage.
using WeakSubscriptionEntry = SubscriptionEntryTemplate<std::weak_ptr<rclcpp::SubscriptionBase>>;
/// Shared ownership GuardCondition entry for storage.
using GuardConditionEntry = EntryTemplate<std::shared_ptr<rclcpp::GuardCondition>>;
/// Weak ownership GuardCondition entry for storage.
using WeakGuardConditionEntry = EntryTemplate<std::weak_ptr<rclcpp::GuardCondition>>;
/// Shared ownership Timer entry for storage.
using TimerEntry = EntryTemplate<std::shared_ptr<rclcpp::TimerBase>>;
/// Weak ownership Timer entry for storage.
using WeakTimerEntry = EntryTemplate<std::weak_ptr<rclcpp::TimerBase>>;
/// Shared ownership Client entry for storage.
using ClientEntry = EntryTemplate<std::shared_ptr<rclcpp::ClientBase>>;
/// Weak ownership Client entry for storage.
using WeakClientEntry = EntryTemplate<std::weak_ptr<rclcpp::ClientBase>>;
/// Shared ownership Service entry for storage.
using ServiceEntry = EntryTemplate<std::shared_ptr<rclcpp::ServiceBase>>;
/// Weak ownership Service entry for storage.
using WeakServiceEntry = EntryTemplate<std::weak_ptr<rclcpp::ServiceBase>>;
/// Shared ownership Waitable entry for storage.
using WaitableEntry = EntryWithAssociatedEntityTemplate<std::shared_ptr<rclcpp::Waitable>>;
/// Weak ownership Waitable entry for storage.
using WeakWaitableEntry = EntryWithAssociatedEntityTemplate<std::weak_ptr<rclcpp::Waitable>>;
} // namespace detail
} // namespace wait_set_policies
} // namespace rclcpp
#endif // RCLCPP__WAIT_SET_POLICIES__DETAIL__ENTRY_TYPES_HPP_

View File

@@ -59,9 +59,7 @@ protected:
const WaitablesIterable & waitables,
rclcpp::Context::SharedPtr context
)
: rcl_wait_set_(rcl_get_zero_initialized_wait_set()),
context_(context),
previous_size_of_extra_guard_conditions_(extra_guard_conditions.size())
: rcl_wait_set_(rcl_get_zero_initialized_wait_set()), context_(context)
{
// Check context is not nullptr.
if (nullptr == context) {
@@ -168,11 +166,6 @@ protected:
)
{
bool was_resized = false;
// Check if the extra_guard_conditions has changed.
if (previous_size_of_extra_guard_conditions_ != extra_guard_conditions.size()) {
previous_size_of_extra_guard_conditions_ = extra_guard_conditions.size();
needs_resize_ = true;
}
// Resize the wait set, but only if it needs to be.
if (needs_resize_) {
// Resizing with rcl_wait_set_resize() is a no-op if nothing has changed,
@@ -242,7 +235,7 @@ protected:
// Add subscriptions.
for (const auto & subscription_entry : subscriptions) {
auto subscription_ptr_pair =
get_raw_pointer_from_smart_pointer(subscription_entry);
get_raw_pointer_from_smart_pointer(subscription_entry.subscription);
if (nullptr == subscription_ptr_pair.second) {
// In this case it was probably stored as a weak_ptr, but is now locking to nullptr.
if (HasStrongOwnership) {
@@ -257,7 +250,7 @@ protected:
rcl_ret_t ret = rcl_wait_set_add_subscription(
&rcl_wait_set_,
subscription_ptr_pair.second->get_subscription_handle().get(),
&subscription_entry.rcl_wait_set_index);
nullptr);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
@@ -283,7 +276,7 @@ protected:
rcl_ret_t ret = rcl_wait_set_add_guard_condition(
&rcl_wait_set_,
&guard_condition_ptr_pair.second->get_rcl_guard_condition(),
&guard_condition.rcl_wait_set_index);
nullptr);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
@@ -313,7 +306,7 @@ protected:
rcl_ret_t ret = rcl_wait_set_add_timer(
&rcl_wait_set_,
timer_ptr_pair.second->get_timer_handle().get(),
&timer.rcl_wait_set_index);
nullptr);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
@@ -336,7 +329,7 @@ protected:
rcl_ret_t ret = rcl_wait_set_add_client(
&rcl_wait_set_,
client_ptr_pair.second->get_client_handle().get(),
&clients.rcl_wait_set_index);
nullptr);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
@@ -359,7 +352,7 @@ protected:
rcl_ret_t ret = rcl_wait_set_add_service(
&rcl_wait_set_,
service_ptr_pair.second->get_service_handle().get(),
&service.rcl_wait_set_index);
nullptr);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
@@ -367,7 +360,7 @@ protected:
// Add waitables.
for (auto & waitable_entry : waitables) {
auto waitable_ptr_pair = get_raw_pointer_from_smart_pointer(waitable_entry);
auto waitable_ptr_pair = get_raw_pointer_from_smart_pointer(waitable_entry.waitable);
if (nullptr == waitable_ptr_pair.second) {
// In this case it was probably stored as a weak_ptr, but is now locking to nullptr.
if (HasStrongOwnership) {
@@ -410,7 +403,6 @@ protected:
bool needs_pruning_ = false;
bool needs_resize_ = false;
size_t previous_size_of_extra_guard_conditions_ = 0;
};
} // namespace detail

View File

@@ -20,9 +20,14 @@
#include <utility>
#include <vector>
#include "rclcpp/client.hpp"
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/service.hpp"
#include "rclcpp/subscription_base.hpp"
#include "rclcpp/subscription_wait_set_mask.hpp"
#include "rclcpp/timer.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/wait_set_policies/detail/entry_types.hpp"
#include "rclcpp/wait_set_policies/detail/storage_policy_common.hpp"
#include "rclcpp/waitable.hpp"
@@ -37,25 +42,126 @@ class DynamicStorage : public rclcpp::wait_set_policies::detail::StoragePolicyCo
protected:
using is_mutable = std::true_type;
using SubscriptionEntry = detail::SubscriptionEntry;
using SequenceOfWeakSubscriptions = std::vector<detail::WeakSubscriptionEntry>;
using SubscriptionsIterable = std::vector<detail::SubscriptionEntry>;
class SubscriptionEntry
{
// (wjwwood): indent of 'public:' is weird, I know. uncrustify is dumb.
using SequenceOfWeakGuardConditions = std::vector<detail::WeakGuardConditionEntry>;
using GuardConditionsIterable = std::vector<detail::GuardConditionEntry>;
public:
std::shared_ptr<rclcpp::SubscriptionBase> subscription;
rclcpp::SubscriptionWaitSetMask mask;
using SequenceOfWeakTimers = std::vector<detail::WeakTimerEntry>;
using TimersIterable = std::vector<detail::TimerEntry>;
/// Conversion constructor, which is intentionally not marked explicit.
SubscriptionEntry(
const std::shared_ptr<rclcpp::SubscriptionBase> & subscription_in = nullptr,
const rclcpp::SubscriptionWaitSetMask & mask_in = {})
: subscription(subscription_in),
mask(mask_in)
{}
using SequenceOfWeakClients = std::vector<detail::WeakClientEntry>;
using ClientsIterable = std::vector<detail::ClientEntry>;
void
reset() noexcept
{
subscription.reset();
}
};
class WeakSubscriptionEntry
{
public:
std::weak_ptr<rclcpp::SubscriptionBase> subscription;
rclcpp::SubscriptionWaitSetMask mask;
using SequenceOfWeakServices = std::vector<detail::WeakServiceEntry>;
using ServicesIterable = std::vector<detail::ServiceEntry>;
explicit WeakSubscriptionEntry(
const std::shared_ptr<rclcpp::SubscriptionBase> & subscription_in,
const rclcpp::SubscriptionWaitSetMask & mask_in) noexcept
: subscription(subscription_in),
mask(mask_in)
{}
using WaitableEntry = detail::WaitableEntry;
using SequenceOfWeakWaitables = std::vector<detail::WeakWaitableEntry>;
using WaitablesIterable = std::vector<detail::WaitableEntry>;
explicit WeakSubscriptionEntry(const SubscriptionEntry & other)
: subscription(other.subscription),
mask(other.mask)
{}
std::shared_ptr<rclcpp::SubscriptionBase>
lock() const
{
return subscription.lock();
}
bool
expired() const noexcept
{
return subscription.expired();
}
};
using SequenceOfWeakSubscriptions = std::vector<WeakSubscriptionEntry>;
using SubscriptionsIterable = std::vector<SubscriptionEntry>;
using SequenceOfWeakGuardConditions = std::vector<std::weak_ptr<rclcpp::GuardCondition>>;
using GuardConditionsIterable = std::vector<std::shared_ptr<rclcpp::GuardCondition>>;
using SequenceOfWeakTimers = std::vector<std::weak_ptr<rclcpp::TimerBase>>;
using TimersIterable = std::vector<std::shared_ptr<rclcpp::TimerBase>>;
using SequenceOfWeakClients = std::vector<std::weak_ptr<rclcpp::ClientBase>>;
using ClientsIterable = std::vector<std::shared_ptr<rclcpp::ClientBase>>;
using SequenceOfWeakServices = std::vector<std::weak_ptr<rclcpp::ServiceBase>>;
using ServicesIterable = std::vector<std::shared_ptr<rclcpp::ServiceBase>>;
class WaitableEntry
{
public:
std::shared_ptr<rclcpp::Waitable> waitable;
std::shared_ptr<void> associated_entity;
/// Conversion constructor, which is intentionally not marked explicit.
WaitableEntry(
const std::shared_ptr<rclcpp::Waitable> & waitable_in = nullptr,
const std::shared_ptr<void> & associated_entity_in = nullptr) noexcept
: waitable(waitable_in),
associated_entity(associated_entity_in)
{}
void
reset() noexcept
{
waitable.reset();
associated_entity.reset();
}
};
class WeakWaitableEntry
{
public:
std::weak_ptr<rclcpp::Waitable> waitable;
std::weak_ptr<void> associated_entity;
explicit WeakWaitableEntry(
const std::shared_ptr<rclcpp::Waitable> & waitable_in,
const std::shared_ptr<void> & associated_entity_in) noexcept
: waitable(waitable_in),
associated_entity(associated_entity_in)
{}
explicit WeakWaitableEntry(const WaitableEntry & other)
: waitable(other.waitable),
associated_entity(other.associated_entity)
{}
std::shared_ptr<rclcpp::Waitable>
lock() const
{
return waitable.lock();
}
bool
expired() const noexcept
{
return waitable.expired();
}
};
using SequenceOfWeakWaitables = std::vector<WeakWaitableEntry>;
using WaitablesIterable = std::vector<WaitableEntry>;
template<class ArrayOfExtraGuardConditions>
explicit
@@ -99,13 +205,13 @@ protected:
storage_rebuild_rcl_wait_set(const ArrayOfExtraGuardConditions & extra_guard_conditions)
{
this->storage_rebuild_rcl_wait_set_with_sets(
shared_subscriptions_,
shared_guard_conditions_,
subscriptions_,
guard_conditions_,
extra_guard_conditions,
shared_timers_,
shared_clients_,
shared_services_,
shared_waitables_
timers_,
clients_,
services_,
waitables_
);
}
@@ -137,7 +243,7 @@ protected:
if (this->storage_has_entity(*subscription, subscriptions_)) {
throw std::runtime_error("subscription already in wait set");
}
detail::WeakSubscriptionEntry weak_entry{std::move(subscription), {}, detail::not_in_wait_set};
WeakSubscriptionEntry weak_entry{std::move(subscription), {}};
subscriptions_.push_back(std::move(weak_entry));
this->storage_flag_for_resize();
}
@@ -159,7 +265,7 @@ protected:
if (this->storage_has_entity(*guard_condition, guard_conditions_)) {
throw std::runtime_error("guard_condition already in wait set");
}
guard_conditions_.push_back({std::move(guard_condition), detail::not_in_wait_set});
guard_conditions_.push_back(std::move(guard_condition));
this->storage_flag_for_resize();
}
@@ -180,7 +286,7 @@ protected:
if (this->storage_has_entity(*timer, timers_)) {
throw std::runtime_error("timer already in wait set");
}
timers_.push_back({std::move(timer), detail::not_in_wait_set});
timers_.push_back(std::move(timer));
this->storage_flag_for_resize();
}
@@ -201,7 +307,7 @@ protected:
if (this->storage_has_entity(*client, clients_)) {
throw std::runtime_error("client already in wait set");
}
clients_.push_back({std::move(client), detail::not_in_wait_set});
clients_.push_back(std::move(client));
this->storage_flag_for_resize();
}
@@ -222,7 +328,7 @@ protected:
if (this->storage_has_entity(*service, services_)) {
throw std::runtime_error("service already in wait set");
}
services_.push_back({std::move(service), detail::not_in_wait_set});
services_.push_back(std::move(service));
this->storage_flag_for_resize();
}
@@ -245,10 +351,7 @@ protected:
if (this->storage_has_entity(*waitable, waitables_)) {
throw std::runtime_error("waitable already in wait set");
}
detail::WeakWaitableEntry weak_entry(
std::move(waitable),
std::move(associated_entity),
detail::not_in_wait_set);
WeakWaitableEntry weak_entry(std::move(waitable), std::move(associated_entity));
waitables_.push_back(std::move(weak_entry));
this->storage_flag_for_resize();
}
@@ -279,7 +382,6 @@ protected:
return weak_ptr.expired();
};
// remove guard conditions which have been deleted
subscriptions_.erase(std::remove_if(subscriptions_.begin(), subscriptions_.end(), p));
guard_conditions_.erase(std::remove_if(guard_conditions_.begin(), guard_conditions_.end(), p));
timers_.erase(std::remove_if(timers_.begin(), timers_.end(), p));
clients_.erase(std::remove_if(clients_.begin(), clients_.end(), p));
@@ -303,7 +405,6 @@ protected:
}
};
// Lock all the weak pointers and hold them until released.
lock_all(subscriptions_, shared_subscriptions_);
lock_all(guard_conditions_, shared_guard_conditions_);
lock_all(timers_, shared_timers_);
lock_all(clients_, shared_clients_);
@@ -314,9 +415,9 @@ protected:
shared_ptrs.resize(weak_ptrs.size());
size_t index = 0;
for (const auto & weak_ptr : weak_ptrs) {
shared_ptrs[index++] = detail::WaitableEntry{
weak_ptr.lock(),
weak_ptr.associated_entity};
shared_ptrs[index++] = WaitableEntry{
weak_ptr.waitable.lock(),
weak_ptr.associated_entity.lock()};
}
};
lock_all_waitables(waitables_, shared_waitables_);
@@ -335,7 +436,6 @@ protected:
shared_ptr.reset();
}
};
reset_all(shared_subscriptions_);
reset_all(shared_guard_conditions_);
reset_all(shared_timers_);
reset_all(shared_clients_);

View File

@@ -26,7 +26,6 @@
#include "rclcpp/subscription_wait_set_mask.hpp"
#include "rclcpp/timer.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/wait_set_policies/detail/entry_types.hpp"
#include "rclcpp/wait_set_policies/detail/storage_policy_common.hpp"
#include "rclcpp/waitable.hpp"
@@ -53,38 +52,65 @@ class StaticStorage : public rclcpp::wait_set_policies::detail::StoragePolicyCom
protected:
using is_mutable = std::false_type;
class SubscriptionEntry
{
public:
std::shared_ptr<rclcpp::SubscriptionBase> subscription;
rclcpp::SubscriptionWaitSetMask mask;
/// Conversion constructor, which is intentionally not marked explicit.
SubscriptionEntry(
const std::shared_ptr<rclcpp::SubscriptionBase> & subscription_in = nullptr,
const rclcpp::SubscriptionWaitSetMask & mask_in = {})
: subscription(subscription_in),
mask(mask_in)
{}
};
using ArrayOfSubscriptions = std::array<
detail::SubscriptionEntry,
SubscriptionEntry,
NumberOfSubscriptions
>;
using SubscriptionsIterable = ArrayOfSubscriptions;
using ArrayOfGuardConditions = std::array<
detail::GuardConditionEntry,
std::shared_ptr<rclcpp::GuardCondition>,
NumberOfGuardCondtions
>;
using GuardConditionsIterable = ArrayOfGuardConditions;
using ArrayOfTimers = std::array<
detail::TimerEntry,
std::shared_ptr<rclcpp::TimerBase>,
NumberOfTimers
>;
using TimersIterable = ArrayOfTimers;
using ArrayOfClients = std::array<
detail::ClientEntry,
std::shared_ptr<rclcpp::ClientBase>,
NumberOfClients
>;
using ClientsIterable = ArrayOfClients;
using ArrayOfServices = std::array<
detail::ServiceEntry,
std::shared_ptr<rclcpp::ServiceBase>,
NumberOfServices
>;
using ServicesIterable = ArrayOfServices;
struct WaitableEntry
{
/// Conversion constructor, which is intentionally not marked explicit.
WaitableEntry(
const std::shared_ptr<rclcpp::Waitable> & waitable_in = nullptr,
const std::shared_ptr<void> & associated_entity_in = nullptr) noexcept
: waitable(waitable_in),
associated_entity(associated_entity_in)
{}
std::shared_ptr<rclcpp::Waitable> waitable;
std::shared_ptr<void> associated_entity;
};
using ArrayOfWaitables = std::array<
detail::WaitableEntry,
WaitableEntry,
NumberOfWaitables
>;
using WaitablesIterable = ArrayOfWaitables;

View File

@@ -73,8 +73,8 @@ public:
const typename StoragePolicy::ClientsIterable & clients = {},
const typename StoragePolicy::ServicesIterable & services = {},
const typename StoragePolicy::WaitablesIterable & waitables = {},
rclcpp::Context::SharedPtr context = (
rclcpp::contexts::get_global_default_context()))
rclcpp::Context::SharedPtr context =
rclcpp::contexts::get_global_default_context())
: SynchronizationPolicy(context),
StoragePolicy(
subscriptions,
@@ -249,7 +249,7 @@ public:
*
* Except in the case of a fixed sized storage, where changes to the wait set
* cannot occur after construction, in which case it holds shared ownership
* at all times until the wait set is destroyed, but this method also does not
* at all times until the wait set is destroy, but this method also does not
* exist on a fixed sized wait set.
*
* This function may be thread-safe depending on the SynchronizationPolicy

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>0.8.3</version>
<version>1.0.0</version>
<description>The ROS client library in C++.</description>
<maintainer email="dthomas@osrfoundation.org">Dirk Thomas</maintainer>
<license>Apache License 2.0</license>
@@ -37,6 +37,7 @@
<test_depend>ament_lint_common</test_depend>
<test_depend>rmw</test_depend>
<test_depend>rmw_implementation_cmake</test_depend>
<test_depend>rosidl_default_generators</test_depend>
<test_depend>test_msgs</test_depend>
<export>

View File

@@ -0,0 +1,111 @@
// 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.
@{
uppercase_interface_name = interface_name.upper()
}@
#ifndef RCLCPP__NODE_INTERFACES__GET_@(uppercase_interface_name)_HPP_
#define RCLCPP__NODE_INTERFACES__GET_@(uppercase_interface_name)_HPP_
#include <memory>
#include <utility>
#include <type_traits>
#include "rcpputils/pointer_traits.hpp"
#include "rclcpp/node_interfaces/@(interface_name).hpp"
#include "rclcpp/node_interfaces/@(interface_name)_traits.hpp"
@{
interface_typename = ''.join([part.capitalize() for part in interface_name.split('_')])
}@
/// This header provides the get_@(interface_name)() template function.
/**
* This function is useful for getting the @(interface_typename) pointer from
* various kinds of Node-like classes.
*
* It's able to get a std::shared_ptr to a @(interface_typename) so long as the class
* has a method called ``get_@(interface_name)()`` which returns one.
*/
namespace rclcpp
{
namespace node_interfaces
{
namespace detail
{
// If NodeType has a method called get_@(interface_name)() which returns a shared pointer.
template<
typename NodeType,
typename std::enable_if<has_@(interface_name)<
typename rcpputils::remove_pointer<NodeType>::type
>::value, int>::type = 0
>
std::shared_ptr<rclcpp::node_interfaces::@(interface_typename)>
get_@(interface_name)_from_pointer(NodeType node_pointer)
{
if (!node_pointer) {
throw std::invalid_argument("node cannot be nullptr");
}
return node_pointer->get_@(interface_name)();
}
} // namespace detail
/// Get the @(interface_typename) as a shared pointer from a pointer to a "Node like" object.
template<
typename NodeType,
typename std::enable_if<
rcpputils::is_pointer<NodeType>::value, int
>::type = 0
>
inline
std::shared_ptr<rclcpp::node_interfaces::@(interface_typename)>
get_@(interface_name)(NodeType && node)
{
// Forward pointers to detail implementation directly.
return detail::get_@(interface_name)_from_pointer(node);
}
/// Get the @(interface_typename) as a shared pointer from a "Node like" object.
template<
typename NodeType,
typename std::enable_if<
!rcpputils::is_pointer<NodeType>::value, int
>::type = 0
>
inline
std::shared_ptr<rclcpp::node_interfaces::@(interface_typename)>
get_@(interface_name)(NodeType && node)
{
// Forward references to detail implementation as a pointer.
return detail::get_@(interface_name)_from_pointer(&node);
}
/// Keep the @(interface_typename) a shared pointer.
inline
std::shared_ptr<rclcpp::node_interfaces::@(interface_typename)>
get_@(interface_name)(
std::shared_ptr<rclcpp::node_interfaces::@(interface_typename)> & node_interface)
{
return node_interface;
}
} // namespace node_interfaces
} // namespace rclcpp
#endif // RCLCPP__NODE_INTERFACES__GET_@(uppercase_interface_name)_HPP_

View File

@@ -0,0 +1,47 @@
// 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.
@{
uppercase_interface_name = interface_name.upper()
interface_typename = ''.join([part.capitalize() for part in interface_name.split('_')])
}@
#ifndef RCLCPP__NODE_INTERFACES__@(uppercase_interface_name)_TRAITS_HPP_
#define RCLCPP__NODE_INTERFACES__@(uppercase_interface_name)_TRAITS_HPP_
#include <functional>
#include <type_traits>
#include "rclcpp/node_interfaces/@(interface_name).hpp"
namespace rclcpp
{
namespace node_interfaces
{
template<class T, typename = void>
struct has_@(interface_name) : std::false_type
{};
template<class T>
struct has_@(interface_name)<
T, typename std::enable_if<
std::is_same<
std::shared_ptr<rclcpp::node_interfaces::@(interface_typename)>,
decltype(std::declval<T>().get_@(interface_name)())>::value>::type> : std::true_type
{};
} // namespace node_interfaces
} // namespace rclcpp
#endif // RCLCPP__NODE_INTERFACES__@(uppercase_interface_name)_TRAITS_HPP_

View File

@@ -22,6 +22,7 @@
#include <utility>
#include "rcl/init.h"
#include "rcl/logging.h"
#include "rclcpp/detail/utilities.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/logging.hpp"
@@ -34,8 +35,27 @@ static std::vector<std::weak_ptr<rclcpp::Context>> g_contexts;
using rclcpp::Context;
static
std::shared_ptr<std::mutex>
get_global_logging_configure_mutex()
{
static auto mutex = std::make_shared<std::mutex>();
return mutex;
}
static
size_t &
get_logging_reference_count()
{
static size_t ref_count = 0;
return ref_count;
}
Context::Context()
: rcl_context_(nullptr), shutdown_reason_("") {}
: rcl_context_(nullptr),
shutdown_reason_(""),
logging_configure_mutex_(nullptr)
{}
Context::~Context()
{
@@ -94,6 +114,30 @@ Context::init(
rcl_context_.reset();
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to initialize rcl");
}
if (init_options.auto_initialize_logging()) {
logging_configure_mutex_ = get_global_logging_configure_mutex();
if (!logging_configure_mutex_) {
throw std::runtime_error("global logging configure mutex is 'nullptr'");
}
std::lock_guard<std::mutex> guard(*logging_configure_mutex_);
size_t & count = get_logging_reference_count();
if (0u == count) {
ret = rcl_logging_configure(
&rcl_context_->global_arguments,
rcl_init_options_get_allocator(init_options_.get_rcl_init_options()));
if (RCL_RET_OK != ret) {
rcl_context_.reset();
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure logging");
}
} else {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"logging was initialized more than once");
}
++count;
}
try {
std::vector<std::string> unparsed_ros_arguments = detail::get_unparsed_ros_arguments(
argc, argv, &(rcl_context_->global_arguments), rcl_get_default_allocator());
@@ -183,6 +227,22 @@ Context::shutdown(const std::string & reason)
++it;
}
}
// shutdown logger
if (logging_configure_mutex_) {
// logging was initialized by this context
std::lock_guard<std::mutex> guard(*logging_configure_mutex_);
size_t & count = get_logging_reference_count();
if (0u == --count) {
rcl_ret_t rcl_ret = rcl_logging_fini();
if (RCL_RET_OK != rcl_ret) {
RCUTILS_SAFE_FWRITE_TO_STDERR(
RCUTILS_STRINGIFY(__file__) ":"
RCUTILS_STRINGIFY(__LINE__)
" failed to fini logging");
rcl_reset_error();
}
}
}
return true;
}

View File

@@ -34,9 +34,48 @@ using rclcpp::Executor;
using rclcpp::ExecutorOptions;
using rclcpp::FutureReturnCode;
Executor::Executor(const ExecutorOptions & options)
: spinning(false), interrupt_guard_condition_(options.context)
Executor::Executor(const rclcpp::ExecutorOptions & options)
: spinning(false),
memory_strategy_(options.memory_strategy)
{
rcl_guard_condition_options_t guard_condition_options = rcl_guard_condition_get_default_options();
rcl_ret_t ret = rcl_guard_condition_init(
&interrupt_guard_condition_, options.context->get_rcl_context().get(), guard_condition_options);
if (RCL_RET_OK != ret) {
throw_from_rcl_error(ret, "Failed to create interrupt guard condition in Executor constructor");
}
// The number of guard conditions is always at least 2: 1 for the ctrl-c guard cond,
// and one for the executor's guard cond (interrupt_guard_condition_)
// Put the global ctrl-c guard condition in
memory_strategy_->add_guard_condition(options.context->get_interrupt_guard_condition(&wait_set_));
// Put the executor's guard condition in
memory_strategy_->add_guard_condition(&interrupt_guard_condition_);
rcl_allocator_t allocator = memory_strategy_->get_allocator();
// Store the context for later use.
context_ = options.context;
ret = rcl_wait_set_init(
&wait_set_,
0, 2, 0, 0, 0, 0,
context_->get_rcl_context().get(),
allocator);
if (RCL_RET_OK != ret) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"failed to create wait set: %s", rcl_get_error_string().str);
rcl_reset_error();
if (rcl_guard_condition_fini(&interrupt_guard_condition_) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"failed to destroy guard condition: %s", rcl_get_error_string().str);
rcl_reset_error();
}
throw std::runtime_error("Failed to create wait set in Executor constructor");
}
}
Executor::~Executor()
@@ -167,6 +206,12 @@ Executor::spin_node_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr n
this->remove_node(node, false);
}
void
Executor::spin_node_some(std::shared_ptr<rclcpp::Node> node)
{
this->spin_node_some(node->get_node_base_interface());
}
void
Executor::spin_some(std::chrono::nanoseconds max_duration)
{
@@ -221,6 +266,15 @@ Executor::cancel()
}
}
void
Executor::set_memory_strategy(rclcpp::memory_strategy::MemoryStrategy::SharedPtr memory_strategy)
{
if (memory_strategy == nullptr) {
throw std::runtime_error("Received NULL memory strategy in executor.");
}
memory_strategy_ = memory_strategy;
}
void
Executor::execute_any_executable(AnyExecutable & any_exec)
{
@@ -296,8 +350,7 @@ Executor::execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
if (subscription->is_serialized()) {
// This is the case where a copy of the serialized message is taken from
// the middleware via inter-process communication.
std::shared_ptr<rcl_serialized_message_t> serialized_msg =
subscription->create_serialized_message();
std::shared_ptr<SerializedMessage> serialized_msg = subscription->create_serialized_message();
take_and_do_error_handling(
"taking a serialized message from topic",
subscription->get_topic_name(),
@@ -549,7 +602,7 @@ Executor::get_next_ready_executable(AnyExecutable & any_executable)
any_executable.callback_group->can_be_taken_from().store(false);
}
}
// If there is no ready executable, return a null ptr
// If there is no ready executable, return false
return success;
}

View File

@@ -46,6 +46,19 @@ InitOptions::InitOptions(const InitOptions & other)
shutdown_on_sigint = other.shutdown_on_sigint;
}
bool
InitOptions::auto_initialize_logging() const
{
return initialize_logging_;
}
InitOptions &
InitOptions::auto_initialize_logging(bool initialize_logging)
{
initialize_logging_ = initialize_logging;
return *this;
}
InitOptions &
InitOptions::operator=(const InitOptions & other)
{

View File

@@ -108,7 +108,7 @@ Node::Node(
node_graph_(new rclcpp::node_interfaces::NodeGraph(node_base_.get())),
node_logging_(new rclcpp::node_interfaces::NodeLogging(node_base_.get())),
node_timers_(new rclcpp::node_interfaces::NodeTimers(node_base_.get())),
node_topics_(new rclcpp::node_interfaces::NodeTopics(node_base_.get())),
node_topics_(new rclcpp::node_interfaces::NodeTopics(node_base_.get(), node_timers_.get())),
node_services_(new rclcpp::node_interfaces::NodeServices(node_base_.get())),
node_clock_(new rclcpp::node_interfaces::NodeClock(
node_base_,
@@ -499,9 +499,3 @@ Node::get_node_options() const
{
return this->node_options_;
}
bool
Node::assert_liveliness() const
{
return node_base_->assert_liveliness();
}

View File

@@ -202,12 +202,6 @@ NodeBase::get_shared_rcl_node_handle() const
return node_handle_;
}
bool
NodeBase::assert_liveliness() const
{
return RCL_RET_OK == rcl_node_assert_liveliness(get_rcl_node_handle());
}
rclcpp::CallbackGroup::SharedPtr
NodeBase::create_callback_group(rclcpp::CallbackGroupType group_type)
{

View File

@@ -107,11 +107,14 @@ NodeParameters::NodeParameters(
rcl_yaml_node_struct_fini(params);
});
rclcpp::ParameterMap initial_map = rclcpp::parameter_map_from(params);
for (auto iter = initial_map.begin(); initial_map.end() != iter; iter++) {
// TODO(cottsay) implement further wildcard matching
if (iter->first == "/**" || iter->first == combined_name_) {
// Enforce wildcard matching precedence
// TODO(cottsay) implement further wildcard matching
const std::vector<std::string> node_matching_names{"/**", combined_name_};
for (const auto & node_name : node_matching_names) {
if (initial_map.count(node_name) > 0) {
// Combine parameter yaml files, overwriting values in older ones
for (auto & param : iter->second) {
for (const rclcpp::Parameter & param : initial_map.at(node_name)) {
parameter_overrides_[param.get_name()] =
rclcpp::ParameterValue(param.get_value_message());
}

View File

@@ -22,8 +22,10 @@ using rclcpp::exceptions::throw_from_rcl_error;
using rclcpp::node_interfaces::NodeTopics;
NodeTopics::NodeTopics(rclcpp::node_interfaces::NodeBaseInterface * node_base)
: node_base_(node_base)
NodeTopics::NodeTopics(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
rclcpp::node_interfaces::NodeTimersInterface * node_timers)
: node_base_(node_base), node_timers_(node_timers)
{}
NodeTopics::~NodeTopics()
@@ -121,3 +123,9 @@ NodeTopics::get_node_base_interface() const
{
return node_base_;
}
rclcpp::node_interfaces::NodeTimersInterface *
NodeTopics::get_node_timers_interface() const
{
return node_timers_;
}

View File

@@ -35,6 +35,7 @@
#include "rclcpp/logging.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/qos_event.hpp"
using rclcpp::PublisherBase;
@@ -246,7 +247,8 @@ PublisherBase::setup_intra_process(
}
void
PublisherBase::default_incompatible_qos_callback(QOSOfferedIncompatibleQoSInfo & event) const
PublisherBase::default_incompatible_qos_callback(
rclcpp::QOSOfferedIncompatibleQoSInfo & event) const
{
std::string policy_name = qos_policy_name_from_kind(event.last_policy_kind);
RCLCPP_WARN(

View File

@@ -55,8 +55,11 @@ void SerializationBase::deserialize_message(
rcpputils::check_true(nullptr != type_support_, "Typesupport is nullpointer.");
rcpputils::check_true(nullptr != serialized_message, "Serialized message is nullpointer.");
rcpputils::check_true(
0 != serialized_message->capacity() && 0 != serialized_message->size(),
"Serialized message is wrongly initialized.");
0u != serialized_message->capacity(),
"Wrongly initialized. Serialized message has a capacity of zero.");
rcpputils::check_true(
0u != serialized_message->size(),
"Wrongly initialized. Serialized message has a size of zero.");
rcpputils::check_true(nullptr != ros_message, "ROS message is a nullpointer.");
const auto ret = rmw_deserialize(

View File

@@ -66,50 +66,51 @@ SerializedMessage::SerializedMessage(const rcl_serialized_message_t & other)
}
SerializedMessage::SerializedMessage(SerializedMessage && other)
: SerializedMessage(other.serialized_message_)
{
other.serialized_message_ = rmw_get_zero_initialized_serialized_message();
}
: serialized_message_(
std::exchange(other.serialized_message_, rmw_get_zero_initialized_serialized_message()))
{}
SerializedMessage::SerializedMessage(rcl_serialized_message_t && other)
: serialized_message_(other)
{
// reset buffer to prevent double free
other = rmw_get_zero_initialized_serialized_message();
}
: serialized_message_(
std::exchange(other, rmw_get_zero_initialized_serialized_message()))
{}
SerializedMessage & SerializedMessage::operator=(const SerializedMessage & other)
{
serialized_message_ = rmw_get_zero_initialized_serialized_message();
copy_rcl_message(other.serialized_message_, serialized_message_);
if (this != &other) {
serialized_message_ = rmw_get_zero_initialized_serialized_message();
copy_rcl_message(other.serialized_message_, serialized_message_);
}
return *this;
}
SerializedMessage & SerializedMessage::operator=(const rcl_serialized_message_t & other)
{
serialized_message_ = rmw_get_zero_initialized_serialized_message();
copy_rcl_message(other, serialized_message_);
if (&serialized_message_ != &other) {
serialized_message_ = rmw_get_zero_initialized_serialized_message();
copy_rcl_message(other, serialized_message_);
}
return *this;
}
SerializedMessage & SerializedMessage::operator=(SerializedMessage && other)
{
*this = other.serialized_message_;
other.serialized_message_ = rmw_get_zero_initialized_serialized_message();
if (this != &other) {
serialized_message_ =
std::exchange(other.serialized_message_, rmw_get_zero_initialized_serialized_message());
}
return *this;
}
SerializedMessage & SerializedMessage::operator=(rcl_serialized_message_t && other)
{
serialized_message_ = rmw_get_zero_initialized_serialized_message();
serialized_message_ = other;
// reset original to prevent double free
other = rmw_get_zero_initialized_serialized_message();
if (&serialized_message_ != &other) {
serialized_message_ =
std::exchange(other, rmw_get_zero_initialized_serialized_message());
}
return *this;
}
@@ -144,4 +145,20 @@ size_t SerializedMessage::capacity() const
{
return serialized_message_.buffer_capacity;
}
void SerializedMessage::reserve(size_t capacity)
{
auto ret = rmw_serialized_message_resize(&serialized_message_, capacity);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
}
rcl_serialized_message_t SerializedMessage::release_rcl_serialized_message()
{
auto ret = serialized_message_;
serialized_message_ = rmw_get_zero_initialized_serialized_message();
return ret;
}
} // namespace rclcpp

View File

@@ -41,7 +41,7 @@ ServiceBase::take_type_erased_request(void * request_out, rmw_request_id_t & req
this->get_service_handle().get(),
&request_id_out,
request_out);
if (RCL_RET_CLIENT_TAKE_FAILED == ret) {
if (RCL_RET_SERVICE_TAKE_FAILED == ret) {
return false;
} else if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);

View File

@@ -24,6 +24,7 @@
#include "rclcpp/experimental/intra_process_manager.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/qos_event.hpp"
#include "rmw/error_handling.h"
#include "rmw/rmw.h"
@@ -159,12 +160,12 @@ SubscriptionBase::take_type_erased(void * message_out, rclcpp::MessageInfo & mes
bool
SubscriptionBase::take_serialized(
rcl_serialized_message_t & message_out,
rclcpp::SerializedMessage & message_out,
rclcpp::MessageInfo & message_info_out)
{
rcl_ret_t ret = rcl_take_serialized_message(
this->get_subscription_handle().get(),
&message_out,
&message_out.get_rcl_serialized_message(),
&message_info_out.get_rmw_message_info(),
nullptr);
if (RCL_RET_SUBSCRIPTION_TAKE_FAILED == ret) {
@@ -238,7 +239,8 @@ SubscriptionBase::get_intra_process_waitable() const
}
void
SubscriptionBase::default_incompatible_qos_callback(QOSRequestedIncompatibleQoSInfo & event) const
SubscriptionBase::default_incompatible_qos_callback(
rclcpp::QOSRequestedIncompatibleQoSInfo & event) const
{
std::string policy_name = qos_policy_name_from_kind(event.last_policy_kind);
RCLCPP_WARN(

View File

@@ -0,0 +1,3 @@
# Simple Header message with a timestamp field.
builtin_interfaces/Time stamp

View File

@@ -0,0 +1,3 @@
# Message containing a simple Header field.
Header header

View File

@@ -47,22 +47,38 @@ protected:
rclcpp::Node::SharedPtr TestGetNodeInterfaces::node = nullptr;
std::shared_ptr<NodeWrapper> TestGetNodeInterfaces::wrapped_node = nullptr;
TEST_F(TestGetNodeInterfaces, null_rclcpp_node_shared_ptr) {
rclcpp::Node::SharedPtr null_node;
EXPECT_THROW(
{
rclcpp::node_interfaces::get_node_topics_interface(null_node);
}, std::invalid_argument);
}
TEST_F(TestGetNodeInterfaces, rclcpp_node_shared_ptr) {
auto result = rclcpp::node_interfaces::get_node_topics_interface(this->node);
static_assert(
std::is_same<
rclcpp::node_interfaces::NodeTopicsInterface *,
std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface>,
decltype(result)
>::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *");
>::value, "expected std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface>");
}
TEST_F(TestGetNodeInterfaces, null_node_shared_ptr) {
std::shared_ptr<NodeWrapper> null_node;
EXPECT_THROW(
{
rclcpp::node_interfaces::get_node_topics_interface(null_node);
}, std::invalid_argument);
}
TEST_F(TestGetNodeInterfaces, node_shared_ptr) {
auto result = rclcpp::node_interfaces::get_node_topics_interface(this->wrapped_node);
static_assert(
std::is_same<
rclcpp::node_interfaces::NodeTopicsInterface *,
std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface>,
decltype(result)
>::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *");
>::value, "expected std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface>");
}
TEST_F(TestGetNodeInterfaces, rclcpp_node_reference) {
@@ -70,9 +86,9 @@ TEST_F(TestGetNodeInterfaces, rclcpp_node_reference) {
auto result = rclcpp::node_interfaces::get_node_topics_interface(node_reference);
static_assert(
std::is_same<
rclcpp::node_interfaces::NodeTopicsInterface *,
std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface>,
decltype(result)
>::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *");
>::value, "expected std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface>");
}
TEST_F(TestGetNodeInterfaces, node_reference) {
@@ -80,9 +96,9 @@ TEST_F(TestGetNodeInterfaces, node_reference) {
auto result = rclcpp::node_interfaces::get_node_topics_interface(wrapped_node_reference);
static_assert(
std::is_same<
rclcpp::node_interfaces::NodeTopicsInterface *,
std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface>,
decltype(result)
>::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *");
>::value, "expected std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface>");
}
TEST_F(TestGetNodeInterfaces, rclcpp_node_pointer) {
@@ -90,9 +106,17 @@ TEST_F(TestGetNodeInterfaces, rclcpp_node_pointer) {
auto result = rclcpp::node_interfaces::get_node_topics_interface(node_pointer);
static_assert(
std::is_same<
rclcpp::node_interfaces::NodeTopicsInterface *,
std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface>,
decltype(result)
>::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *");
>::value, "expected std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface>");
}
TEST_F(TestGetNodeInterfaces, null_rclcpp_node_pointer) {
rclcpp::Node * null_node{nullptr};
EXPECT_THROW(
{
rclcpp::node_interfaces::get_node_topics_interface(null_node);
}, std::invalid_argument);
}
TEST_F(TestGetNodeInterfaces, node_pointer) {
@@ -100,9 +124,17 @@ TEST_F(TestGetNodeInterfaces, node_pointer) {
auto result = rclcpp::node_interfaces::get_node_topics_interface(wrapped_node_pointer);
static_assert(
std::is_same<
rclcpp::node_interfaces::NodeTopicsInterface *,
std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface>,
decltype(result)
>::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *");
>::value, "expected std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface>");
}
TEST_F(TestGetNodeInterfaces, null_node_pointer) {
NodeWrapper * null_node{nullptr};
EXPECT_THROW(
{
rclcpp::node_interfaces::get_node_topics_interface(null_node);
}, std::invalid_argument);
}
TEST_F(TestGetNodeInterfaces, interface_shared_pointer) {
@@ -111,7 +143,7 @@ TEST_F(TestGetNodeInterfaces, interface_shared_pointer) {
auto result = rclcpp::node_interfaces::get_node_topics_interface(interface_shared_ptr);
static_assert(
std::is_same<
rclcpp::node_interfaces::NodeTopicsInterface *,
std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface>,
decltype(result)
>::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *");
>::value, "expected std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface>");
}

View File

@@ -1,4 +1,8 @@
/**:
ros__parameters:
parameter_int: 21
parameter_bool: true
parameter_int: 42
parameter_string_array: [baz, baz, baz]
test_declare_parameter_node:
ros__parameters:
parameter_int: 21

View File

@@ -0,0 +1,78 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <memory>
#include <utility>
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/node_interfaces/node_base_interface_traits.hpp"
#include "rclcpp/node_interfaces/node_base.hpp"
#include "rclcpp/node.hpp"
class MyNode
{
public:
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> get_node_base_interface() const
{
rclcpp::NodeOptions options;
return std::make_shared<rclcpp::node_interfaces::NodeBase>(
"my_node_name",
"my_node_namespace",
rclcpp::contexts::get_global_default_context(),
*options.get_rcl_node_options(),
options.use_intra_process_comms(),
options.enable_topic_statistics());
}
};
class WrongNode
{
public:
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> not_get_node_base_interface()
{
return nullptr;
}
};
template<class T, typename std::enable_if<
rclcpp::node_interfaces::has_node_base_interface<T>::value
>::type * = nullptr>
void get_node_name(const T & nodelike)
{
ASSERT_STREQ("my_node_name", nodelike.get_node_base_interface()->get_name());
}
class TestInterfaceTraits : public ::testing::Test
{
protected:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
};
TEST_F(TestInterfaceTraits, has_node_base_interface) {
ASSERT_TRUE(rclcpp::node_interfaces::has_node_base_interface<MyNode>::value);
ASSERT_FALSE(rclcpp::node_interfaces::has_node_base_interface<WrongNode>::value);
ASSERT_TRUE(rclcpp::node_interfaces::has_node_base_interface<rclcpp::Node>::value);
get_node_name(MyNode());
}

View File

@@ -691,7 +691,7 @@ TEST_F(TestNode, declare_parameter_with_cli_overrides) {
no.arguments(
{
"--ros-args",
"-p", "parameter_bool:=true",
"-p", "parameter_bool:=false",
"-p", "parameter_int:=42",
"-p", "parameter_double:=0.42",
"-p", "parameter_string:=foo",
@@ -702,7 +702,8 @@ TEST_F(TestNode, declare_parameter_with_cli_overrides) {
"-p", "parameter_string_array:=[foo, bar]"
});
auto node = std::make_shared<rclcpp::Node>("test_declare_parameter_node"_unq, no);
// To match parameters YAML file content, use a well-known node name for this test only.
auto node = std::make_shared<rclcpp::Node>("test_declare_parameter_node", no);
{
rclcpp::ParameterValue value = node->declare_parameter("parameter_bool");
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_BOOL);
@@ -2590,7 +2591,7 @@ TEST_F(TestNode, get_publishers_subscriptions_info_by_topic) {
RMW_QOS_POLICY_DURABILITY_VOLATILE,
{15, 1678},
{29, 2345},
RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_NODE,
RMW_QOS_POLICY_LIVELINESS_AUTOMATIC,
{5, 23456},
false
};

View File

@@ -15,8 +15,8 @@
#include <gtest/gtest.h>
#include <iostream>
#include <string>
#include <memory>
#include <string>
#include "rclcpp/exceptions.hpp"
#include "rclcpp/publisher.hpp"
@@ -51,6 +51,10 @@ public:
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
protected:
void SetUp() {}

View File

@@ -65,7 +65,7 @@ TEST(TestQoS, equality_liveliness) {
EXPECT_NE(a, b);
b.liveliness_lease_duration(duration);
EXPECT_EQ(a, b);
a.liveliness(RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_NODE);
a.liveliness(RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC);
EXPECT_NE(a, b);
}

View File

@@ -52,6 +52,7 @@ TEST(TestSerializedMessage, various_constructors) {
rcl_handle.buffer_length = content_size;
EXPECT_STREQ(content.c_str(), reinterpret_cast<char *>(rcl_handle.buffer));
EXPECT_EQ(content_size, serialized_message.capacity());
EXPECT_EQ(content_size, serialized_message.size());
// Copy Constructor
rclcpp::SerializedMessage other_serialized_message(serialized_message);
@@ -114,6 +115,31 @@ TEST(TestSerializedMessage, various_constructors_from_rcl) {
EXPECT_TRUE(nullptr != rcl_handle.buffer);
}
TEST(TestSerializedMessage, release) {
const std::string content = "Hello World";
const auto content_size = content.size() + 1; // accounting for null terminator
rcl_serialized_message_t released_handle = rmw_get_zero_initialized_serialized_message();
{
rclcpp::SerializedMessage serialized_msg(13);
// manually copy some content
auto & rcl_serialized_msg = serialized_msg.get_rcl_serialized_message();
std::memcpy(rcl_serialized_msg.buffer, content.c_str(), content.size());
rcl_serialized_msg.buffer[content.size()] = '\0';
rcl_serialized_msg.buffer_length = content_size;
EXPECT_EQ(13u, serialized_msg.capacity());
released_handle = serialized_msg.release_rcl_serialized_message();
// scope exit of serialized_msg
}
EXPECT_TRUE(nullptr != released_handle.buffer);
EXPECT_EQ(13u, released_handle.buffer_capacity);
EXPECT_EQ(content_size, released_handle.buffer_length);
// cleanup memory manually
EXPECT_EQ(RCL_RET_OK, rmw_serialized_message_fini(&released_handle));
}
TEST(TestSerializedMessage, serialization) {
using MessageT = test_msgs::msg::BasicTypes;
@@ -133,9 +159,9 @@ TEST(TestSerializedMessage, serialization) {
}
}
template<typename MessageT>
void test_empty_msg_serialize()
void serialize_default_ros_msg()
{
using MessageT = test_msgs::msg::BasicTypes;
rclcpp::Serialization<MessageT> serializer;
MessageT ros_msg;
rclcpp::SerializedMessage serialized_msg;
@@ -143,12 +169,40 @@ void test_empty_msg_serialize()
serializer.serialize_message(&ros_msg, &serialized_msg);
}
template<typename MessageT>
void test_empty_msg_deserialize()
void serialize_default_ros_msg_into_nullptr()
{
using MessageT = test_msgs::msg::BasicTypes;
rclcpp::Serialization<MessageT> serializer;
MessageT ros_msg;
serializer.serialize_message(&ros_msg, nullptr);
}
void deserialize_default_serialized_message()
{
using MessageT = test_msgs::msg::BasicTypes;
rclcpp::Serialization<MessageT> serializer;
MessageT ros_msg;
rclcpp::SerializedMessage serialized_msg;
serializer.deserialize_message(&serialized_msg, &ros_msg);
}
void deserialize_nullptr()
{
using MessageT = test_msgs::msg::BasicTypes;
rclcpp::Serialization<MessageT> serializer;
MessageT ros_msg;
rclcpp::SerializedMessage serialized_msg;
serializer.deserialize_message(&serialized_msg, &ros_msg);
}
TEST(TestSerializedMessage, serialization_empty_messages)
{
EXPECT_NO_THROW(serialize_default_ros_msg());
EXPECT_THROW(serialize_default_ros_msg_into_nullptr(), rcpputils::IllegalStateException);
EXPECT_THROW(serialize_default_ros_msg_into_nullptr(), rcpputils::IllegalStateException);
EXPECT_THROW(deserialize_default_serialized_message(), rcpputils::IllegalStateException);
EXPECT_THROW(deserialize_nullptr(), rcpputils::IllegalStateException);
}

View File

@@ -29,25 +29,25 @@ TEST(TestSerializedMessageAllocator, default_allocator) {
rclcpp::message_memory_strategy::MessageMemoryStrategy<DummyMessageT>::create_default();
auto msg0 = mem_strategy->borrow_serialized_message();
ASSERT_EQ(msg0->buffer_capacity, 0u);
ASSERT_EQ(msg0->capacity(), 0u);
mem_strategy->return_serialized_message(msg0);
auto msg100 = mem_strategy->borrow_serialized_message(100);
ASSERT_EQ(msg100->buffer_capacity, 100u);
ASSERT_EQ(msg100->capacity(), 100u);
mem_strategy->return_serialized_message(msg100);
auto msg200 = mem_strategy->borrow_serialized_message();
auto ret = rmw_serialized_message_resize(msg200.get(), 200);
auto ret = rmw_serialized_message_resize(&msg200->get_rcl_serialized_message(), 200);
ASSERT_EQ(RCL_RET_OK, ret);
EXPECT_EQ(0u, msg200->buffer_length);
EXPECT_EQ(200u, msg200->buffer_capacity);
EXPECT_EQ(0u, msg200->size());
EXPECT_EQ(200u, msg200->capacity());
mem_strategy->return_serialized_message(msg200);
auto msg1000 = mem_strategy->borrow_serialized_message(1000);
ASSERT_EQ(msg1000->buffer_capacity, 1000u);
ret = rmw_serialized_message_resize(msg1000.get(), 2000);
ASSERT_EQ(msg1000->capacity(), 1000u);
ret = rmw_serialized_message_resize(&msg1000->get_rcl_serialized_message(), 2000);
ASSERT_EQ(RCL_RET_OK, ret);
EXPECT_EQ(2000u, msg1000->buffer_capacity);
EXPECT_EQ(2000u, msg1000->capacity());
mem_strategy->return_serialized_message(msg1000);
}
@@ -61,7 +61,7 @@ TEST(TestSerializedMessageAllocator, borrow_from_subscription) {
[](std::shared_ptr<test_msgs::msg::Empty> test_msg) {(void) test_msg;});
auto msg0 = sub->create_serialized_message();
EXPECT_EQ(0u, msg0->buffer_capacity);
EXPECT_EQ(0u, msg0->capacity());
sub->return_serialized_message(msg0);
rclcpp::shutdown();

View File

@@ -299,10 +299,10 @@ TEST_F(TestSubscription, take) {
TEST_F(TestSubscription, take_serialized) {
initialize();
using test_msgs::msg::Empty;
auto do_nothing = [](std::shared_ptr<const rcl_serialized_message_t>) {FAIL();};
auto do_nothing = [](std::shared_ptr<const rclcpp::SerializedMessage>) {FAIL();};
{
auto sub = node->create_subscription<test_msgs::msg::Empty>("~/test_take", 1, do_nothing);
std::shared_ptr<rcl_serialized_message_t> msg = sub->create_serialized_message();
std::shared_ptr<rclcpp::SerializedMessage> msg = sub->create_serialized_message();
rclcpp::MessageInfo msg_info;
EXPECT_FALSE(sub->take_serialized(*msg, msg_info));
}
@@ -317,7 +317,7 @@ TEST_F(TestSubscription, take_serialized) {
test_msgs::msg::Empty msg;
pub->publish(msg);
}
std::shared_ptr<rcl_serialized_message_t> msg = sub->create_serialized_message();
std::shared_ptr<rclcpp::SerializedMessage> msg = sub->create_serialized_message();
rclcpp::MessageInfo msg_info;
bool message_recieved = false;
auto start = std::chrono::steady_clock::now();

View File

@@ -44,6 +44,10 @@ public:
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
protected:
void SetUp() {}

View File

@@ -67,13 +67,13 @@ TEST(TestSubscriptionTraits, is_serialized_callback) {
// Test regular functions
auto cb1 = &serialized_callback_copy;
static_assert(
rclcpp::subscription_traits::is_serialized_callback<decltype(cb1)>::value == true,
"rcl_serialized_message_t in a first argument callback makes it a serialized callback");
rclcpp::subscription_traits::is_serialized_callback<decltype(cb1)>::value == false,
"passing a rcl_serialized_message_t * is not a serialized callback");
auto cb2 = &serialized_callback_shared_ptr;
static_assert(
rclcpp::subscription_traits::is_serialized_callback<decltype(cb2)>::value == true,
"std::shared_ptr<rcl_serialized_message_t> in a callback makes it a serialized callback");
rclcpp::subscription_traits::is_serialized_callback<decltype(cb2)>::value == false,
"passing a std::shared_ptr<rcl_serialized_message_t> is not a serialized callback");
auto cb3 = &not_serialized_callback;
static_assert(
@@ -90,8 +90,8 @@ TEST(TestSubscriptionTraits, is_serialized_callback) {
(void) unused;
};
static_assert(
rclcpp::subscription_traits::is_serialized_callback<decltype(cb5)>::value == true,
"rcl_serialized_message_t in a first argument callback makes it a serialized callback");
rclcpp::subscription_traits::is_serialized_callback<decltype(cb5)>::value == false,
"passing rcl_serialized_message_t is not a serialized callback");
using MessageT = test_msgs::msg::Empty;
using MessageTAllocator = std::allocator<void>;

View File

@@ -14,33 +14,49 @@
#include <gtest/gtest.h>
#include <atomic>
#include <chrono>
#include <iostream>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "libstatistics_collector/moving_average_statistics/types.hpp"
#include "rclcpp/create_publisher.hpp"
#include "rclcpp/msg/message_with_header.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/subscription_options.hpp"
#include "rclcpp/topic_statistics/subscription_topic_statistics.hpp"
#include "statistics_msgs/msg/metrics_message.hpp"
#include "statistics_msgs/msg/statistic_data_point.hpp"
#include "statistics_msgs/msg/statistic_data_type.hpp"
#include "test_msgs/msg/empty.hpp"
#include "test_topic_stats_utils.hpp"
namespace
{
constexpr const char kTestNodeName[]{"test_sub_stats_node"};
constexpr const char kTestPubNodeName[]{"test_pub_stats_node"};
constexpr const char kTestSubNodeName[]{"test_sub_stats_node"};
constexpr const char kTestSubStatsTopic[]{"/test_sub_stats_topic"};
constexpr const char kTestTopicStatisticsTopic[]{"/test_topic_statistics_topic"};
constexpr const uint64_t kNoSamples{0};
constexpr const std::chrono::seconds kTestDuration{10};
} // namespace
using rclcpp::msg::MessageWithHeader;
using test_msgs::msg::Empty;
using statistics_msgs::msg::MetricsMessage;
using rclcpp::topic_statistics::SubscriptionTopicStatistics;
using statistics_msgs::msg::MetricsMessage;
using statistics_msgs::msg::StatisticDataPoint;
using statistics_msgs::msg::StatisticDataType;
using libstatistics_collector::moving_average_statistics::StatisticData;
template<typename CallbackMessageT>
@@ -63,6 +79,70 @@ public:
}
};
/**
* Empty publisher node: used to publish empty messages
*/
class EmptyPublisher : public rclcpp::Node
{
public:
EmptyPublisher(
const std::string & name, const std::string & topic,
const std::chrono::milliseconds & publish_period = std::chrono::milliseconds{100})
: Node(name)
{
publisher_ = create_publisher<Empty>(topic, 10);
publish_timer_ = this->create_wall_timer(
publish_period, [this]() {
this->publish_message();
});
}
virtual ~EmptyPublisher() = default;
private:
void publish_message()
{
auto msg = Empty{};
publisher_->publish(msg);
}
rclcpp::Publisher<Empty>::SharedPtr publisher_;
rclcpp::TimerBase::SharedPtr publish_timer_;
};
/**
* MessageWithHeader publisher node: used to publish MessageWithHeader with `header` value set
*/
class MessageWithHeaderPublisher : public rclcpp::Node
{
public:
MessageWithHeaderPublisher(
const std::string & name, const std::string & topic,
const std::chrono::milliseconds & publish_period = std::chrono::milliseconds{100})
: Node(name)
{
publisher_ = create_publisher<MessageWithHeader>(topic, 10);
publish_timer_ = this->create_wall_timer(
publish_period, [this]() {
this->publish_message();
});
}
virtual ~MessageWithHeaderPublisher() = default;
private:
void publish_message()
{
auto msg = MessageWithHeader{};
// Subtract 1 sec from current time so the received message age is always > 0
msg.header.stamp = this->now() - rclcpp::Duration{1, 0};
publisher_->publish(msg);
}
rclcpp::Publisher<MessageWithHeader>::SharedPtr publisher_;
rclcpp::TimerBase::SharedPtr publish_timer_;
};
/**
* Empty subscriber node: used to create subscriber topic statistics requirements
*/
@@ -72,26 +152,55 @@ public:
EmptySubscriber(const std::string & name, const std::string & topic)
: Node(name)
{
auto callback = [this](Empty::UniquePtr msg) {
this->receive_message(*msg);
// manually enable topic statistics via options
auto options = rclcpp::SubscriptionOptions();
options.topic_stats_options.state = rclcpp::TopicStatisticsState::Enable;
auto callback = [](Empty::UniquePtr msg) {
(void) msg;
};
subscription_ = create_subscription<Empty,
std::function<void(Empty::UniquePtr)>>(
topic,
rclcpp::QoS(rclcpp::KeepAll()),
callback);
callback,
options);
}
virtual ~EmptySubscriber() = default;
private:
void receive_message(const Empty &) const
{
}
rclcpp::Subscription<Empty>::SharedPtr subscription_;
};
/**
* MessageWithHeader subscriber node: used to create subscriber topic statistics requirements
*/
class MessageWithHeaderSubscriber : public rclcpp::Node
{
public:
MessageWithHeaderSubscriber(const std::string & name, const std::string & topic)
: Node(name)
{
// manually enable topic statistics via options
auto options = rclcpp::SubscriptionOptions();
options.topic_stats_options.state = rclcpp::TopicStatisticsState::Enable;
auto callback = [](MessageWithHeader::UniquePtr msg) {
(void) msg;
};
subscription_ = create_subscription<MessageWithHeader,
std::function<void(MessageWithHeader::UniquePtr)>>(
topic,
rclcpp::QoS(rclcpp::KeepAll()),
callback,
options);
}
virtual ~MessageWithHeaderSubscriber() = default;
private:
rclcpp::Subscription<MessageWithHeader>::SharedPtr subscription_;
};
/**
* Test fixture to bring up and teardown rclcpp
*/
@@ -102,7 +211,7 @@ protected:
{
rclcpp::init(0 /* argc */, nullptr /* argv */);
empty_subscriber = std::make_shared<EmptySubscriber>(
kTestNodeName,
kTestSubNodeName,
kTestSubStatsTopic);
}
@@ -116,20 +225,18 @@ protected:
TEST_F(TestSubscriptionTopicStatisticsFixture, test_manual_construction)
{
// manually create publisher tied to the node
// Manually create publisher tied to the node
auto topic_stats_publisher =
empty_subscriber->create_publisher<MetricsMessage>(
kTestTopicStatisticsTopic,
10);
// construct the instance
// Construct a separate instance
auto sub_topic_stats = std::make_unique<TestSubscriptionTopicStatistics<Empty>>(
empty_subscriber->get_name(),
topic_stats_publisher);
using libstatistics_collector::moving_average_statistics::StatisticData;
// expect no data has been collected / no samples received
// Expect no data has been collected / no samples received
for (const auto & data : sub_topic_stats->get_current_collector_data()) {
EXPECT_TRUE(std::isnan(data.average));
EXPECT_TRUE(std::isnan(data.min));
@@ -138,3 +245,148 @@ TEST_F(TestSubscriptionTopicStatisticsFixture, test_manual_construction)
EXPECT_EQ(kNoSamples, data.sample_count);
}
}
TEST_F(TestSubscriptionTopicStatisticsFixture, test_receive_stats_for_message_no_header)
{
// Create an empty publisher
auto empty_publisher = std::make_shared<EmptyPublisher>(
kTestPubNodeName,
kTestSubStatsTopic);
// empty_subscriber has a topic statistics instance as part of its subscription
// this will listen to and generate statistics for the empty message
// Create a listener for topic statistics messages
auto statistics_listener = std::make_shared<rclcpp::topic_statistics::MetricsMessageSubscriber>(
"test_receive_single_empty_stats_message_listener",
"/statistics",
2);
rclcpp::executors::SingleThreadedExecutor ex;
ex.add_node(empty_publisher);
ex.add_node(statistics_listener);
ex.add_node(empty_subscriber);
// Spin and get future
ex.spin_until_future_complete(
statistics_listener->GetFuture(),
kTestDuration);
// Compare message counts, sample count should be the same as published and received count
EXPECT_EQ(2, statistics_listener->GetNumberOfMessagesReceived());
// Check the received message and the data types
const auto received_messages = statistics_listener->GetReceivedMessages();
EXPECT_EQ(2u, received_messages.size());
std::set<std::string> received_metrics;
for (const auto & msg : received_messages) {
received_metrics.insert(msg.metrics_source);
}
EXPECT_TRUE(received_metrics.find("message_age") != received_metrics.end());
EXPECT_TRUE(received_metrics.find("message_period") != received_metrics.end());
// Check the collected statistics for message period.
// Message age statistics will not be calculated because Empty messages
// don't have a `header` with timestamp.
for (const auto & msg : received_messages) {
if (msg.metrics_source != "message_period") {
continue;
}
for (const auto & stats_point : msg.statistics) {
const auto type = stats_point.data_type;
switch (type) {
case StatisticDataType::STATISTICS_DATA_TYPE_SAMPLE_COUNT:
EXPECT_LT(0, stats_point.data) << "unexpected sample count";
break;
case StatisticDataType::STATISTICS_DATA_TYPE_AVERAGE:
EXPECT_LT(0, stats_point.data) << "unexpected avg";
break;
case StatisticDataType::STATISTICS_DATA_TYPE_MINIMUM:
EXPECT_LT(0, stats_point.data) << "unexpected min";
break;
case StatisticDataType::STATISTICS_DATA_TYPE_MAXIMUM:
EXPECT_LT(0, stats_point.data) << "unexpected max";
break;
case StatisticDataType::STATISTICS_DATA_TYPE_STDDEV:
EXPECT_LT(0, stats_point.data) << "unexpected stddev";
break;
default:
FAIL() << "received unknown statistics type: " << std::dec <<
static_cast<unsigned int>(type);
}
}
}
}
TEST_F(TestSubscriptionTopicStatisticsFixture, test_receive_stats_for_message_with_header)
{
// Create a MessageWithHeader publisher
auto msg_with_header_publisher = std::make_shared<MessageWithHeaderPublisher>(
kTestPubNodeName,
kTestSubStatsTopic);
// empty_subscriber has a topic statistics instance as part of its subscription
// this will listen to and generate statistics for the empty message
// Create a listener for topic statistics messages
auto statistics_listener = std::make_shared<rclcpp::topic_statistics::MetricsMessageSubscriber>(
"test_receive_stats_for_message_with_header",
"/statistics",
2);
auto msg_with_header_subscriber = std::make_shared<MessageWithHeaderSubscriber>(
kTestSubNodeName,
kTestSubStatsTopic);
rclcpp::executors::SingleThreadedExecutor ex;
ex.add_node(msg_with_header_publisher);
ex.add_node(statistics_listener);
ex.add_node(msg_with_header_subscriber);
// Spin and get future
ex.spin_until_future_complete(
statistics_listener->GetFuture(),
kTestDuration);
// Compare message counts, sample count should be the same as published and received count
EXPECT_EQ(2, statistics_listener->GetNumberOfMessagesReceived());
// Check the received message and the data types
const auto received_messages = statistics_listener->GetReceivedMessages();
EXPECT_EQ(2u, received_messages.size());
std::set<std::string> received_metrics;
for (const auto & msg : received_messages) {
received_metrics.insert(msg.metrics_source);
}
EXPECT_TRUE(received_metrics.find("message_age") != received_metrics.end());
EXPECT_TRUE(received_metrics.find("message_period") != received_metrics.end());
// Check the collected statistics for message period.
for (const auto & msg : received_messages) {
for (const auto & stats_point : msg.statistics) {
const auto type = stats_point.data_type;
switch (type) {
case StatisticDataType::STATISTICS_DATA_TYPE_SAMPLE_COUNT:
EXPECT_LT(0, stats_point.data) << "unexpected sample count";
break;
case StatisticDataType::STATISTICS_DATA_TYPE_AVERAGE:
EXPECT_LT(0, stats_point.data) << "unexpected avg";
break;
case StatisticDataType::STATISTICS_DATA_TYPE_MINIMUM:
EXPECT_LT(0, stats_point.data) << "unexpected min";
break;
case StatisticDataType::STATISTICS_DATA_TYPE_MAXIMUM:
EXPECT_LT(0, stats_point.data) << "unexpected max";
break;
case StatisticDataType::STATISTICS_DATA_TYPE_STDDEV:
EXPECT_LE(0, stats_point.data) << "unexpected stddev";
break;
default:
FAIL() << "received unknown statistics type: " << std::dec <<
static_cast<unsigned int>(type);
}
}
}
}

View File

@@ -0,0 +1,152 @@
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// 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 <atomic>
#include <functional>
#include <future>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#include "statistics_msgs/msg/metrics_message.hpp"
#ifndef TOPIC_STATISTICS__TEST_TOPIC_STATS_UTILS_HPP_
#define TOPIC_STATISTICS__TEST_TOPIC_STATS_UTILS_HPP_
namespace rclcpp
{
namespace topic_statistics
{
using statistics_msgs::msg::MetricsMessage;
/**
* Provide an interface to wait for a promise to be satisfied via its future.
*/
class PromiseSetter
{
public:
/**
* Reassign the promise member and return it's future. Acquires a mutex in order
* to mutate member variables.
*
* \return the promise member's future, called upon PeriodicMeasurement
*/
std::shared_future<bool> GetFuture()
{
std::unique_lock<std::mutex> ulock{mutex_};
use_future_ = true;
promise_ = std::promise<bool>();
return promise_.get_future();
}
protected:
/**
* Set the promise to true, which signals the corresponding future. Acquires a mutex and sets
* the promise to true iff GetFuture was invoked before this.
*/
void SetPromise()
{
std::unique_lock<std::mutex> ulock{mutex_};
if (use_future_) {
// only set if GetFuture was called
promise_.set_value(true);
use_future_ = false; // the promise needs to be reassigned to set again
}
}
private:
mutable std::mutex mutex_;
std::promise<bool> promise_;
bool use_future_{false};
};
/**
* Node which listens for published MetricsMessages. This uses the PromiseSetter API
* in order to signal, via a future, that rclcpp should stop spinning upon
* message handling.
*/
class MetricsMessageSubscriber : public rclcpp::Node, public PromiseSetter
{
public:
/**
* Constructs a MetricsMessageSubscriber.
* \param name the node name
* \param name the topic name
* \param number of messages to receive to trigger the PromiseSetter future
*/
MetricsMessageSubscriber(
const std::string & name,
const std::string & topic_name,
const int number_of_messages_to_receive = 2)
: rclcpp::Node(name),
number_of_messages_to_receive_(number_of_messages_to_receive)
{
auto callback = [this](MetricsMessage::UniquePtr msg) {
this->MetricsMessageCallback(*msg);
};
subscription_ = create_subscription<MetricsMessage,
std::function<void(MetricsMessage::UniquePtr)>>(
topic_name,
10 /*history_depth*/,
callback);
}
/**
* Acquires a mutex in order to get the last message received member.
* \return the last message received
*/
std::vector<MetricsMessage> GetReceivedMessages() const
{
std::unique_lock<std::mutex> ulock{mutex_};
return received_messages_;
}
/**
* Return the number of messages received by this subscriber.
* \return the number of messages received by the subscriber callback
*/
int GetNumberOfMessagesReceived() const
{
return num_messages_received_;
}
private:
/**
* Subscriber callback. Acquires a mutex to set the last message received and
* sets the promise to true.
* \param msg
*/
void MetricsMessageCallback(const MetricsMessage & msg)
{
std::unique_lock<std::mutex> ulock{mutex_};
++num_messages_received_;
received_messages_.push_back(msg);
if (num_messages_received_ >= number_of_messages_to_receive_) {
PromiseSetter::SetPromise();
}
}
std::vector<MetricsMessage> received_messages_;
rclcpp::Subscription<MetricsMessage>::SharedPtr subscription_;
mutable std::mutex mutex_;
std::atomic<int> num_messages_received_{0};
const int number_of_messages_to_receive_;
};
} // namespace topic_statistics
} // namespace rclcpp
#endif // TOPIC_STATISTICS__TEST_TOPIC_STATS_UTILS_HPP_

View File

@@ -3,6 +3,26 @@ Changelog for package rclcpp_action
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1.0.0 (2020-05-12)
------------------
0.9.1 (2020-05-08)
------------------
* Added Quality declaration: rclcpp, rclpp_action, rclcpp_components andrclcpp_lifecycle (`#1100 <https://github.com/ros2/rclcpp/issues/1100>`_)
* Contributors: Alejandro Hernández Cordero
0.9.0 (2020-04-29)
------------------
* Increasing test coverage of rclcpp_action (`#1043 <https://github.com/ros2/rclcpp/issues/1043>`_)
* Export targets in addition to include directories / libraries (`#1096 <https://github.com/ros2/rclcpp/issues/1096>`_)
* Deprecate redundant namespaces (`#1083 <https://github.com/ros2/rclcpp/issues/1083>`_)
* Rename rosidl_generator_c namespace to rosidl_runtime_c (`#1062 <https://github.com/ros2/rclcpp/issues/1062>`_)
* Changed rosidl_generator_c/cpp to rosidl_runtime_c/cpp (`#1014 <https://github.com/ros2/rclcpp/issues/1014>`_)
* Fix unknown macro errors reported by cppcheck 1.90 (`#1000 <https://github.com/ros2/rclcpp/issues/1000>`_)
* Removed rosidl_generator_c dependency (`#992 <https://github.com/ros2/rclcpp/issues/992>`_)
* Fix typo in action client logger name (`#937 <https://github.com/ros2/rclcpp/issues/937>`_)
* Contributors: Alejandro Hernández Cordero, Dirk Thomas, Jacob Perron, Stephen Brawner, William Woodall
0.8.3 (2019-11-19)
------------------
* issue-919 Fixed "memory leak" in action clients (`#920 <https://github.com/ros2/rclcpp/issues/920>`_)

View File

@@ -16,8 +16,6 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
include_directories(include)
set(${PROJECT_NAME}_SRCS
src/client.cpp
src/qos.cpp
@@ -29,6 +27,11 @@ set(${PROJECT_NAME}_SRCS
add_library(${PROJECT_NAME}
${${PROJECT_NAME}_SRCS})
target_include_directories(${PROJECT_NAME}
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:include>")
ament_target_dependencies(${PROJECT_NAME}
"action_msgs"
"rcl_action"
@@ -47,6 +50,7 @@ install(
install(
TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
@@ -55,6 +59,7 @@ install(
# specific order: dependents before dependencies
ament_export_include_directories(include)
ament_export_libraries(${PROJECT_NAME})
ament_export_targets(${PROJECT_NAME})
ament_export_dependencies(ament_cmake)
ament_export_dependencies(action_msgs)
@@ -98,6 +103,16 @@ if(BUILD_TESTING)
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_types test/test_types.cpp)
if(TARGET test_types)
ament_target_dependencies(test_types
"test_msgs"
)
target_link_libraries(test_types
${PROJECT_NAME}
)
endif()
endif()
ament_package()

View File

@@ -0,0 +1,166 @@
This document is a declaration of software quality for the `rclcpp_action` package, based on the guidelines in [REP-2004](https://github.com/ros-infrastructure/rep/blob/rep-2004/rep-2004.rst).
# `rclcpp_action` Quality Declaration
The package `rclcpp_action` claims to be in the **Quality Level 4** category.
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#package-quality-categories) of the ROS2 developer guide.
## Version Policy [1]
### Version Scheme [1.i]
`rclcpp_action` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#versioning)
### Version Stability [1.ii]
`rclcpp_action` is not yet at a stable version, i.e. `>= 1.0.0`.
The current version can be found in its [package.xml](package.xml), and its change history can be found in its [CHANGELOG](CHANGELOG.rst).
### Public API Declaration [1.iii]
All symbols in the installed headers are considered part of the public API.
All installed headers are in the `include` directory of the package, headers in any other folders are not installed and considered private.
### API Stability Policy [1.iv]
`rclcpp_action` will not break public API within a released ROS distribution, i.e. no major releases once the ROS distribution is released.
### ABI Stability Policy [1.v]
`rclcpp_action` contains C++ code and therefore must be concerned with ABI stability, and will maintain ABI stability within a ROS distribution.
### ABI and ABI Stability Within a Released ROS Distribution [1.vi]
`rclcpp_action` will not break API nor ABI within a released ROS distribution, i.e. no major releases once the ROS distribution is released.
## Change Control Process [2]
`rclcpp_action` follows the recommended guidelines for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process).
### Change Requests [2.i]
All changes will occur through a pull request, check [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process) for additional information.
### Contributor Origin [2.ii]
This package uses DCO as its confirmation of contributor origin policy. More information can be found in [CONTRIBUTING](../CONTRIBUTING.md).
### Peer Review Policy [2.iii]
All pull requests will be peer-reviewed, check [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process) for additional information.
### Continuous Integration [2.iv]
All pull requests must pass CI on all [tier 1 platforms](https://www.ros.org/reps/rep-2000.html#support-tiers)
Currently nightly results can be seen here:
* [linux-aarch64_release](https://ci.ros2.org/view/nightly/job/nightly_linux-aarch64_release/lastBuild/testReport/rclcpp_action/)
* [linux_release](https://ci.ros2.org/view/nightly/job/nightly_linux_release/lastBuild/testReport/rclcpp_action/)
* [mac_osx_release](https://ci.ros2.org/view/nightly/job/nightly_osx_release/lastBuild/testReport/rclcpp_action/)
* [windows_release](https://ci.ros2.org/view/nightly/job/nightly_win_rel/lastBuild/testReport/rclcpp_action/)
### Documentation Policy [2.v]
All pull requests must resolve related documentation changes before merging.
## Documentation [3]
### Feature Documentation [3.i]
`rclcpp_action` has a [feature list](http://docs.ros2.org/latest/api/rclcpp_action/) and each item in the list links to the corresponding feature documentation. There is documentation for all of the features, and new features require documentation before being added.
### Public API Documentation [3.ii]
The API is publicly available in the [ROS 2 API documentation](http://docs.ros2.org/latest/api/rclcpp_action/).
### License [3.iii]
The license for `rclcpp_action` is Apache 2.0, and a summary is in each source file, the type is declared in the [`package.xml`](./package.xml) manifest file, and a full copy of the license is in the [`LICENSE`](../LICENSE) file.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Epr/job/Epr__rclcpp_action__ubuntu_bionic_amd64/lastBuild/testReport/rclcpp_action/) can be found a list with the latest results of the various linters being run on the package.
### Copyright Statements [3.iv]
The copyright holders each provide a statement of copyright in each source code file in `rclcpp_action`.
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Epr/job/Epr__rclcpp_action__ubuntu_bionic_amd64/lastBuild/testReport/rclcpp_action/copyright/).
## Testing [4]
### Feature Testing [4.i]
Each feature in `rclcpp_action` has corresponding tests which simulate typical usage, and they are located in the [`test`](https://github.com/ros2/rclcpp_action/tree/master/test) directory.
New features are required to have tests before being added.
Currently nightly test results can be seen here:
* [linux-aarch64_release](https://ci.ros2.org/view/nightly/job/nightly_linux-aarch64_release/lastBuild/testReport/rclcpp_action/)
* [linux_release](https://ci.ros2.org/view/nightly/job/nightly_linux_release/lastBuild/testReport/rclcpp_action/)
* [mac_osx_release](https://ci.ros2.org/view/nightly/job/nightly_osx_release/lastBuild/testReport/rclcpp_action/)
* [windows_release](https://ci.ros2.org/view/nightly/job/nightly_win_rel/lastBuild/testReport/rclcpp_action/)
### Public API Testing [4.ii]
Each part of the public API has tests, and new additions or changes to the public API require tests before being added.
The tests aim to cover both typical usage and corner cases, but are quantified by contributing to code coverage.
### Coverage [4.iii]
`rclcpp_action` follows the recommendations for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#code-coverage), and opts to use line coverage instead of branch coverage.
This includes:
- tracking and reporting line coverage statistics
- achieving and maintaining a reasonable branch line coverage (90-100%)
- no lines are manually skipped in coverage calculations
Changes are required to make a best effort to keep or increase coverage before being accepted, but decreases are allowed if properly justified and accepted by reviewers.
### Performance [4.iv]
It is not yet defined if this package requires performance testing and how addresses this topic.
### Linters and Static Analysis [4.v]
`rclcpp_action` uses and passes all the ROS2 standard linters and static analysis tools for a C++ package as described in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#linters-and-static-analysis). Passing implies there are no linter/static errors when testing against CI of supported platforms.
Currently nightly test results can be seen here:
* [linux-aarch64_release](https://ci.ros2.org/view/nightly/job/nightly_linux-aarch64_release/lastBuild/testReport/rclcpp_action/)
* [linux_release](https://ci.ros2.org/view/nightly/job/nightly_linux_release/lastBuild/testReport/rclcpp_action/)
* [mac_osx_release](https://ci.ros2.org/view/nightly/job/nightly_osx_release/lastBuild/testReport/rclcpp_action/)
* [windows_release](https://ci.ros2.org/view/nightly/job/nightly_win_rel/lastBuild/testReport/rclcpp_action/)
## Dependencies [5]
### Direct and Optional Runtime ROS Dependencies [5.i]/[5.ii]
`rclcpp_action` has the following runtime ROS dependencies:
- action_msgs
- rclcpp
- rcl_action
It has several "buildtool" dependencies, which do not affect the resulting quality of the package, because they do not contribute to the public library API.
It also has several test dependencies, which do not affect the resulting quality of the package, because they are only used to build and run the test code.
### Direct Runtime non-ROS Dependency [5.iii]
`rclcpp_action` has no run-time or build-time dependencies that need to be considered for this declaration.
## 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.
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/)
* [linux_release](https://ci.ros2.org/view/nightly/job/nightly_linux_release/lastBuild/rclcpp_action/)
* [mac_osx_release](https://ci.ros2.org/view/nightly/job/nightly_osx_release/lastBuild/rclcpp_action/)
* [windows_release](https://ci.ros2.org/view/nightly/job/nightly_win_rel/lastBuild/rclcpp_action/)
## Security
### Vulnerability Disclosure Policy [7.i]
This package does not yet have a Vulnerability Disclosure Policy

7
rclcpp_action/README.md Normal file
View File

@@ -0,0 +1,7 @@
# `rclcpp_action`
Adds action APIs for C++. Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp_action/) for a complete list of its main components or the [design document](http://design.ros2.org/articles/actions.html).
## Quality Declaration
This package claims to be in the **Quality Level 4** category, see the [Quality Declaration](QUALITY_DECLARATION.md) for more details.

View File

@@ -104,7 +104,7 @@ create_client(
const std::string & name,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
{
return create_client<ActionT>(
return rclcpp_action::create_client<ActionT>(
node->get_node_base_interface(),
node->get_node_graph_interface(),
node->get_node_logging_interface(),

View File

@@ -65,11 +65,11 @@ create_server(
typename Server<ActionT>::CancelCallback handle_cancel,
typename Server<ActionT>::AcceptedCallback handle_accepted,
const rcl_action_server_options_t & options = rcl_action_server_get_default_options(),
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr)
rclcpp::CallbackGroup::SharedPtr group = nullptr)
{
std::weak_ptr<rclcpp::node_interfaces::NodeWaitablesInterface> weak_node =
node_waitables_interface;
std::weak_ptr<rclcpp::callback_group::CallbackGroup> weak_group = group;
std::weak_ptr<rclcpp::CallbackGroup> weak_group = group;
bool group_is_null = (nullptr == group.get());
auto deleter = [weak_node, weak_group, group_is_null](Server<ActionT> * ptr)
@@ -137,7 +137,7 @@ create_server(
typename Server<ActionT>::CancelCallback handle_cancel,
typename Server<ActionT>::AcceptedCallback handle_accepted,
const rcl_action_server_options_t & options = rcl_action_server_get_default_options(),
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr)
rclcpp::CallbackGroup::SharedPtr group = nullptr)
{
return create_server<ActionT>(
node->get_node_base_interface(),

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>0.8.3</version>
<version>1.0.0</version>
<description>Adds action APIs for C++.</description>
<maintainer email="dthomas@osrfoundation.org">Dirk Thomas</maintainer>
<license>Apache License 2.0</license>

View File

@@ -270,6 +270,21 @@ TEST_F(TestClient, construction_and_destruction)
ASSERT_NO_THROW(rclcpp_action::create_client<ActionType>(client_node, action_name).reset());
}
TEST_F(TestClient, construction_and_destruction_callback_group)
{
auto group = client_node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
ASSERT_NO_THROW(
rclcpp_action::create_client<ActionType>(
client_node->get_node_base_interface(),
client_node->get_node_graph_interface(),
client_node->get_node_logging_interface(),
client_node->get_node_waitables_interface(),
action_name,
group
).reset());
}
TEST_F(TestClient, async_send_goal_no_callbacks)
{
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);

View File

@@ -49,7 +49,7 @@ protected:
request->goal_id.uuid = uuid;
auto future = client->async_send_request(request);
if (
rclcpp::executor::FutureReturnCode::SUCCESS !=
rclcpp::FutureReturnCode::SUCCESS !=
rclcpp::spin_until_future_complete(node, future))
{
throw std::runtime_error("send goal future didn't complete succesfully");
@@ -69,7 +69,7 @@ protected:
request->goal_info.goal_id.uuid = uuid;
auto future = cancel_client->async_send_request(request);
if (
rclcpp::executor::FutureReturnCode::SUCCESS !=
rclcpp::FutureReturnCode::SUCCESS !=
rclcpp::spin_until_future_complete(node, future))
{
throw std::runtime_error("cancel goal future didn't complete succesfully");
@@ -95,6 +95,32 @@ TEST_F(TestServer, construction_and_destruction)
(void)as;
}
TEST_F(TestServer, construction_and_destruction_callback_group)
{
auto node = std::make_shared<rclcpp::Node>("construct_node", "/rclcpp_action/construct");
auto group = node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
const rcl_action_server_options_t & options = rcl_action_server_get_default_options();
using GoalHandle = rclcpp_action::ServerGoalHandle<Fibonacci>;
ASSERT_NO_THROW(
rclcpp_action::create_server<Fibonacci>(
node->get_node_base_interface(),
node->get_node_clock_interface(),
node->get_node_logging_interface(),
node->get_node_waitables_interface(),
"fibonacci",
[](const GoalUUID &, std::shared_ptr<const Fibonacci::Goal>) {
return rclcpp_action::GoalResponse::REJECT;
},
[](std::shared_ptr<GoalHandle>) {
return rclcpp_action::CancelResponse::REJECT;
},
[](std::shared_ptr<GoalHandle>) {},
options,
group));
}
TEST_F(TestServer, handle_goal_called)
{
auto node = std::make_shared<rclcpp::Node>("handle_goal_node", "/rclcpp_action/handle_goal");
@@ -132,7 +158,7 @@ TEST_F(TestServer, handle_goal_called)
auto future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::executor::FutureReturnCode::SUCCESS,
rclcpp::FutureReturnCode::SUCCESS,
rclcpp::spin_until_future_complete(node, future));
ASSERT_EQ(uuid, received_uuid);
@@ -744,7 +770,7 @@ TEST_F(TestServer, get_result)
// Wait for the result request to be received
ASSERT_EQ(
rclcpp::executor::FutureReturnCode::SUCCESS,
rclcpp::FutureReturnCode::SUCCESS,
rclcpp::spin_until_future_complete(node, future));
auto response = future.get();

View File

@@ -0,0 +1,61 @@
// 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 <limits>
#include "rclcpp_action/types.hpp"
TEST(TestActionTypes, goal_uuid_to_string) {
rclcpp_action::GoalUUID goal_id;
for (uint8_t i = 0; i < UUID_SIZE; ++i) {
goal_id[i] = i;
}
EXPECT_STREQ("0123456789abcdef", rclcpp_action::to_string(goal_id).c_str());
for (uint8_t i = 0; i < UUID_SIZE; ++i) {
goal_id[i] = 16u + i;
}
EXPECT_STREQ("101112131415161718191a1b1c1d1e1f", rclcpp_action::to_string(goal_id).c_str());
for (uint8_t i = 0; i < UUID_SIZE; ++i) {
goal_id[i] = std::numeric_limits<uint8_t>::max() - i;
}
EXPECT_STREQ("fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0", rclcpp_action::to_string(goal_id).c_str());
}
TEST(TestActionTypes, goal_uuid_to_rcl_action_goal_info) {
rclcpp_action::GoalUUID goal_id;
for (uint8_t i = 0; i < UUID_SIZE; ++i) {
goal_id[i] = i;
}
rcl_action_goal_info_t goal_info = rcl_action_get_zero_initialized_goal_info();
rclcpp_action::convert(goal_id, &goal_info);
for (uint8_t i = 0; i < UUID_SIZE; ++i) {
EXPECT_EQ(goal_info.goal_id.uuid[i], goal_id[i]);
}
}
TEST(TestActionTypes, rcl_action_goal_info_to_goal_uuid) {
rcl_action_goal_info_t goal_info = rcl_action_get_zero_initialized_goal_info();
for (uint8_t i = 0; i < UUID_SIZE; ++i) {
goal_info.goal_id.uuid[i] = i;
}
rclcpp_action::GoalUUID goal_id;
rclcpp_action::convert(goal_id, &goal_info);
for (uint8_t i = 0; i < UUID_SIZE; ++i) {
EXPECT_EQ(goal_info.goal_id.uuid[i], goal_id[i]);
}
}

View File

@@ -2,6 +2,36 @@
Changelog for package rclcpp_components
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1.0.0 (2020-05-12)
------------------
* Increasing test coverage of rclcpp_components (`#1044 <https://github.com/ros2/rclcpp/issues/1044>`_)
* Increasing test coverage of rclcpp_components
Signed-off-by: Stephen Brawner <brawner@gmail.com>
* PR fixup
Signed-off-by: Stephen Brawner <brawner@gmail.com>
* Fixup
Signed-off-by: Stephen Brawner <brawner@gmail.com>
* Removing throws test for now
Signed-off-by: Stephen Brawner <brawner@gmail.com>
* Contributors: brawner
0.9.1 (2020-05-08)
------------------
* Added Quality declaration: rclcpp, rclpp_action, rclcpp_components andrclcpp_lifecycle (`#1100 <https://github.com/ros2/rclcpp/issues/1100>`_)
* Contributors: Alejandro Hernández Cordero
0.9.0 (2020-04-29)
------------------
* Added rclcpp_components Doxyfile (`#1091 <https://github.com/ros2/rclcpp/issues/1091>`_)
* Deprecate redundant namespaces (`#1083 <https://github.com/ros2/rclcpp/issues/1083>`_)
* Export targets in addition to include directories / libraries (`#1088 <https://github.com/ros2/rclcpp/issues/1088>`_)
* Export component manager (`#1070 <https://github.com/ros2/rclcpp/issues/1070>`_)
* Install the component_manager library (`#1068 <https://github.com/ros2/rclcpp/issues/1068>`_)
* Make Component Manager public (`#1065 <https://github.com/ros2/rclcpp/issues/1065>`_)
* Remove absolute path from installed CMake code (`#948 <https://github.com/ros2/rclcpp/issues/948>`_)
* Fix function docblock, check for unparsed arguments (`#945 <https://github.com/ros2/rclcpp/issues/945>`_)
* Contributors: Alejandro Hernández Cordero, DensoADAS, Dirk Thomas, Jacob Perron, Karsten Knese, Michael Carroll, William Woodall
0.8.3 (2019-11-19)
------------------

View File

@@ -17,13 +17,14 @@ find_package(composition_interfaces REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rcpputils REQUIRED)
include_directories(include)
add_library(
component_manager
SHARED
src/component_manager.cpp
)
target_include_directories(component_manager PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:include>")
ament_target_dependencies(component_manager
"ament_index_cpp"
"class_loader"
@@ -68,6 +69,7 @@ if(BUILD_TESTING)
set(components "")
add_library(test_component SHARED test/components/test_component.cpp)
target_include_directories(test_component PUBLIC include)
ament_target_dependencies(test_component
"class_loader"
"rclcpp")
@@ -76,11 +78,19 @@ if(BUILD_TESTING)
set(components "${components}test_rclcpp_components::TestComponentBar;$<TARGET_FILE:test_component>\n")
set(components "${components}test_rclcpp_components::TestComponentNoNode;$<TARGET_FILE:test_component>\n")
# A properly formed resource only has one ';', this is used to catch an invalid resource entry
set(invalid_components "test_rclcpp_components::TestComponentFoo;;$<TARGET_FILE:test_component>\n")
file(GENERATE
OUTPUT
"${CMAKE_CURRENT_BINARY_DIR}/test_ament_index/$<CONFIG>/share/ament_index/resource_index/rclcpp_components/${PROJECT_NAME}"
CONTENT "${components}")
file(GENERATE
OUTPUT
"${CMAKE_CURRENT_BINARY_DIR}/test_ament_index/$<CONFIG>/share/ament_index/resource_index/rclcpp_components/invalid_${PROJECT_NAME}"
CONTENT "${invalid_components}")
set(append_library_dirs "${CMAKE_CURRENT_BINARY_DIR}")
if(WIN32)
set(append_library_dirs "${append_library_dirs}/$<CONFIG>")
@@ -102,7 +112,7 @@ if(BUILD_TESTING)
endif()
install(
TARGETS component_manager
TARGETS component_manager EXPORT component_manager
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
@@ -129,6 +139,8 @@ install(
# specific order: dependents before dependencies
ament_export_include_directories(include)
ament_export_libraries(component_manager)
ament_export_targets(component_manager)
ament_export_dependencies(ament_index_cpp)
ament_export_dependencies(class_loader)
ament_export_dependencies(composition_interfaces)
ament_export_dependencies(rclcpp)

View File

@@ -0,0 +1,33 @@
# All settings not listed here will use the Doxygen default values.
PROJECT_NAME = "rclcpp_components"
PROJECT_NUMBER = master
PROJECT_BRIEF = "Package containing tools for dynamically loadable components"
# Use these lines to include the generated logging.hpp (update install path if needed)
# Otherwise just generate for the local (non-generated header files)
INPUT = ./include
RECURSIVE = YES
OUTPUT_DIRECTORY = doc_output
EXTRACT_ALL = YES
SORT_MEMBER_DOCS = NO
GENERATE_LATEX = NO
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
PREDEFINED = RCLCPP_COMPONENTS_PUBLIC=
# Tag files that do not exist will produce a warning and cross-project linking will not work.
TAGFILES += "../../../../doxygen_tag_files/cppreference-doxygen-web.tag.xml=http://en.cppreference.com/w/"
# Consider changing "latest" to the version you want to reference (e.g. beta1 or 1.0.0)
TAGFILES += "../../../../doxygen_tag_files/class_loader.tag=http://docs.ros2.org/latest/api/class_loader/"
TAGFILES += "../../../../doxygen_tag_files/rclcpp.tag=http://docs.ros2.org/latest/api/rclcpp/"
TAGFILES += "../../../../doxygen_tag_files/rcl.tag=http://docs.ros2.org/latest/api/rcl/"
TAGFILES += "../../../../doxygen_tag_files/rcutils.tag=http://docs.ros2.org/latest/api/rcutils/"
TAGFILES += "../../../../doxygen_tag_files/rmw.tag=http://docs.ros2.org/latest/api/rmw/"
# Uncomment to generate tag files for cross-project linking.
GENERATE_TAGFILE = "../../../../doxygen_tag_files/rclcpp_components.tag"

View File

@@ -0,0 +1,169 @@
This document is a declaration of software quality for the `rclcpp_components` package, based on the guidelines in [REP-2004](https://github.com/ros-infrastructure/rep/blob/rep-2004/rep-2004.rst).
# `rclcpp_components` Quality Declaration
The package `rclcpp_components` claims to be in the **Quality Level 4** category.
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#package-quality-categories) of the ROS2 developer guide.
## Version Policy [1]
### Version Scheme [1.i]
`rclcpp_components` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#versioning)
### Version Stability [1.ii]
`rclcpp_components` is not yet at a stable version, i.e. `>= 1.0.0`.
The current version can be found in its [package.xml](package.xml), and its change history can be found in its [CHANGELOG](CHANGELOG.rst).
### Public API Declaration [1.iii]
All symbols in the installed headers are considered part of the public API.
All installed headers are in the `include` directory of the package, headers in any other folders are not installed and considered private.
### API Stability Policy [1.iv]
`rclcpp_components` will not break public API within a released ROS distribution, i.e. no major releases once the ROS distribution is released.
### ABI Stability Policy [1.v]
`rclcpp_components` contains C++ code and therefore must be concerned with ABI stability, and will maintain ABI stability within a ROS distribution.
### ABI and ABI Stability Within a Released ROS Distribution [1.vi]
`rclcpp_components` will not break API nor ABI within a released ROS distribution, i.e. no major releases once the ROS distribution is released.
## Change Control Process [2]
`rclcpp_components` follows the recommended guidelines for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process).
### Change Requests [2.i]
All changes will occur through a pull request, check [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process) for additional information.
### Contributor Origin [2.ii]
This package uses DCO as its confirmation of contributor origin policy. More information can be found in [CONTRIBUTING](../CONTRIBUTING.md).
### Peer Review Policy [2.iii]
All pull requests will be peer-reviewed, check [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process) for additional information.
### Continuous Integration [2.iv]
All pull requests must pass CI on all [tier 1 platforms](https://www.ros.org/reps/rep-2000.html#support-tiers)
Currently nightly results can be seen here:
* [linux-aarch64_release](https://ci.ros2.org/view/nightly/job/nightly_linux-aarch64_release/lastBuild/testReport/rclcpp_components/)
* [linux_release](https://ci.ros2.org/view/nightly/job/nightly_linux_release/lastBuild/testReport/rclcpp_components/)
* [mac_osx_release](https://ci.ros2.org/view/nightly/job/nightly_osx_release/lastBuild/testReport/rclcpp_components/)
* [windows_release](https://ci.ros2.org/view/nightly/job/nightly_win_rel/lastBuild/testReport/rclcpp_components/)
### Documentation Policy [2.v]
All pull requests must resolve related documentation changes before merging.
## Documentation [3]
### Feature Documentation [3.i]
`rclcpp_components` does not have a documented feature list.
### Public API Documentation [3.ii]
`rclcpp_components` does not cover a public API documentation.
The API is publicly available in the [ROS 2 API documentation](http://docs.ros2.org/latest/api/rclcpp_components/).
### License [3.iii]
The license for `rclcpp_components` is Apache 2.0, and a summary is in each source file, the type is declared in the [`package.xml`](./package.xml) manifest file, and a full copy of the license is in the [`LICENSE`](../LICENSE) file.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Epr/job/Epr__rclcpp_components__ubuntu_bionic_amd64/lastBuild/testReport/rclcpp_components/) can be found a list with the latest results of the various linters being run on the package.
### Copyright Statements [3.iv]
The copyright holders each provide a statement of copyright in each source code file in `rclcpp_components`.
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Epr/job/Epr__rclcpp_components__ubuntu_bionic_amd64/lastBuild/testReport/rclcpp_components/copyright/).
## Testing [4]
### Feature Testing [4.i]
Each feature in `rclcpp_components` has corresponding tests which simulate typical usage, and they are located in the [`test`](https://github.com/ros2/rclcpp_components/tree/master/test) directory.
New features are required to have tests before being added.
Currently nightly test results can be seen here:
* [linux-aarch64_release](https://ci.ros2.org/view/nightly/job/nightly_linux-aarch64_release/lastBuild/testReport/rclcpp_components/)
* [linux_release](https://ci.ros2.org/view/nightly/job/nightly_linux_release/lastBuild/testReport/rclcpp_components/)
* [mac_osx_release](https://ci.ros2.org/view/nightly/job/nightly_osx_release/lastBuild/testReport/rclcpp_components/)
* [windows_release](https://ci.ros2.org/view/nightly/job/nightly_win_rel/lastBuild/testReport/rclcpp_components/)
### Public API Testing [4.ii]
Each part of the public API has tests, and new additions or changes to the public API require tests before being added.
The tests aim to cover both typical usage and corner cases, but are quantified by contributing to code coverage.
### Coverage [4.iii]
`rclcpp_components` follows the recommendations for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#code-coverage), and opts to use line coverage instead of branch coverage.
This includes:
- tracking and reporting line coverage statistics
- achieving and maintaining a reasonable branch line coverage (90-100%)
- no lines are manually skipped in coverage calculations
Changes are required to make a best effort to keep or increase coverage before being accepted, but decreases are allowed if properly justified and accepted by reviewers.
### Performance [4.iv]
It is not yet defined if this package requires performance testing and how addresses this topic.
### Linters and Static Analysis [4.v]
`rclcpp_components` uses and passes all the ROS2 standard linters and static analysis tools for a C++ package as described in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#linters-and-static-analysis). Passing implies there are no linter/static errors when testing against CI of supported platforms.
Currently nightly test results can be seen here:
* [linux-aarch64_release](https://ci.ros2.org/view/nightly/job/nightly_linux-aarch64_release/lastBuild/testReport/rclcpp_components/)
* [linux_release](https://ci.ros2.org/view/nightly/job/nightly_linux_release/lastBuild/testReport/rclcpp_components/)
* [mac_osx_release](https://ci.ros2.org/view/nightly/job/nightly_osx_release/lastBuild/testReport/rclcpp_components/)
* [windows_release](https://ci.ros2.org/view/nightly/job/nightly_win_rel/lastBuild/testReport/rclcpp_components/)
## Dependencies [5]
### Direct and Optional Runtime ROS Dependencies [5.i]/[5.ii]
`rclcpp_components` has the following runtime ROS dependencies:
- ament_index_cpp
- class_loader
- composition_interfaces
- rclcpp
It has several "buildtool" dependencies, which do not affect the resulting quality of the package, because they do not contribute to the public library API.
It also has several test dependencies, which do not affect the resulting quality of the package, because they are only used to build and run the test code.
### Direct Runtime non-ROS Dependency [5.iii]
`rclcpp_components` has no run-time or build-time dependencies that need to be considered for this declaration.
## 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.
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/)
* [linux_release](https://ci.ros2.org/view/nightly/job/nightly_linux_release/lastBuild/rclcpp_components/)
* [mac_osx_release](https://ci.ros2.org/view/nightly/job/nightly_osx_release/lastBuild/rclcpp_components/)
* [windows_release](https://ci.ros2.org/view/nightly/job/nightly_win_rel/lastBuild/rclcpp_components/)
## Security
### Vulnerability Disclosure Policy [7.i]
This package does not yet have a Vulnerability Disclosure Policy

View File

@@ -0,0 +1,7 @@
# `rclcpp_components`
Package containing tools for dynamically loadable components.
## Quality Declaration
This package claims to be in the **Quality Level 4** category, see the [Quality Declaration](QUALITY_DECLARATION.md) for more details.

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>0.8.3</version>
<version>1.0.0</version>
<description>Package containing tools for dynamically loadable components</description>
<maintainer email="michael@openrobotics.org">Michael Carroll</maintainer>
<license>Apache License 2.0</license>

View File

@@ -22,7 +22,6 @@
#include "ament_index_cpp/get_resource.hpp"
#include "class_loader/class_loader.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rcpputils/filesystem_helper.hpp"
#include "rcpputils/split.hpp"

View File

@@ -55,7 +55,6 @@ private:
rclcpp::Node node_;
};
} // namespace test_rclcpp_components
#include "rclcpp_components/register_node_macro.hpp"

View File

@@ -88,4 +88,9 @@ TEST_F(TestComponentManager, create_component_factory_invalid)
auto resources = manager->get_component_resources("rclcpp_components");
auto factory = manager->create_component_factory({"foo_class", resources[0].second});
EXPECT_EQ(nullptr, factory);
// Test improperly formed resources file
EXPECT_THROW(
auto resources = manager->get_component_resources("invalid_rclcpp_components"),
rclcpp_components::ComponentManagerException);
}

View File

@@ -143,6 +143,65 @@ TEST_F(TestComponentManager, components_api)
EXPECT_EQ(result.get()->unique_id, 0u);
}
{
// Remap rules
auto request = std::make_shared<composition_interfaces::srv::LoadNode::Request>();
request->package_name = "rclcpp_components";
request->plugin_name = "test_rclcpp_components::TestComponentFoo";
request->node_name = "test_component_remap";
request->remap_rules.push_back("alice:=bob");
auto result = client->async_send_request(request);
auto ret = exec->spin_until_future_complete(result, 5s); // Wait for the result.
EXPECT_EQ(ret, rclcpp::FutureReturnCode::SUCCESS);
EXPECT_EQ(result.get()->success, true);
EXPECT_EQ(result.get()->error_message, "");
EXPECT_EQ(result.get()->full_node_name, "/test_component_remap");
EXPECT_EQ(result.get()->unique_id, 5u);
}
{
// use_intra_process_comms
auto request = std::make_shared<composition_interfaces::srv::LoadNode::Request>();
request->package_name = "rclcpp_components";
request->plugin_name = "test_rclcpp_components::TestComponentFoo";
request->node_name = "test_component_intra_process";
rclcpp::Parameter use_intraprocess_comms("use_intra_process_comms",
rclcpp::ParameterValue(true));
request->extra_arguments.push_back(use_intraprocess_comms.to_parameter_msg());
auto result = client->async_send_request(request);
auto ret = exec->spin_until_future_complete(result, 5s); // Wait for the result.
EXPECT_EQ(ret, rclcpp::FutureReturnCode::SUCCESS);
EXPECT_EQ(result.get()->success, true);
EXPECT_EQ(result.get()->error_message, "");
std::cout << result.get()->full_node_name << std::endl;
EXPECT_EQ(result.get()->full_node_name, "/test_component_intra_process");
EXPECT_EQ(result.get()->unique_id, 6u);
}
{
// use_intra_process_comms is not a bool type parameter
auto request = std::make_shared<composition_interfaces::srv::LoadNode::Request>();
request->package_name = "rclcpp_components";
request->plugin_name = "test_rclcpp_components::TestComponentFoo";
request->node_name = "test_component_intra_process_str";
rclcpp::Parameter use_intraprocess_comms("use_intra_process_comms",
rclcpp::ParameterValue("hello"));
request->extra_arguments.push_back(use_intraprocess_comms.to_parameter_msg());
auto result = client->async_send_request(request);
auto ret = exec->spin_until_future_complete(result, 5s); // Wait for the result.
EXPECT_EQ(ret, rclcpp::FutureReturnCode::SUCCESS);
EXPECT_EQ(result.get()->success, false);
EXPECT_EQ(
result.get()->error_message,
"Extra component argument 'use_intra_process_comms' must be a boolean");
EXPECT_EQ(result.get()->full_node_name, "");
EXPECT_EQ(result.get()->unique_id, 0u);
}
auto node_names = node->get_node_names();
auto find_in_nodes = [node_names](std::string name) {
@@ -170,16 +229,20 @@ TEST_F(TestComponentManager, components_api)
auto node_names = result.get()->full_node_names;
auto unique_ids = result.get()->unique_ids;
EXPECT_EQ(node_names.size(), 4u);
EXPECT_EQ(node_names.size(), 6u);
EXPECT_EQ(node_names[0], "/test_component_foo");
EXPECT_EQ(node_names[1], "/test_component_bar");
EXPECT_EQ(node_names[2], "/test_component_baz");
EXPECT_EQ(node_names[3], "/ns/test_component_bing");
EXPECT_EQ(unique_ids.size(), 4u);
EXPECT_EQ(node_names[4], "/test_component_remap");
EXPECT_EQ(node_names[5], "/test_component_intra_process");
EXPECT_EQ(unique_ids.size(), 6u);
EXPECT_EQ(unique_ids[0], 1u);
EXPECT_EQ(unique_ids[1], 2u);
EXPECT_EQ(unique_ids[2], 3u);
EXPECT_EQ(unique_ids[3], 4u);
EXPECT_EQ(unique_ids[4], 5u);
EXPECT_EQ(unique_ids[5], 6u);
}
}
@@ -230,14 +293,18 @@ TEST_F(TestComponentManager, components_api)
auto node_names = result.get()->full_node_names;
auto unique_ids = result.get()->unique_ids;
EXPECT_EQ(node_names.size(), 3u);
EXPECT_EQ(node_names.size(), 5u);
EXPECT_EQ(node_names[0], "/test_component_bar");
EXPECT_EQ(node_names[1], "/test_component_baz");
EXPECT_EQ(node_names[2], "/ns/test_component_bing");
EXPECT_EQ(unique_ids.size(), 3u);
EXPECT_EQ(node_names[3], "/test_component_remap");
EXPECT_EQ(node_names[4], "/test_component_intra_process");
EXPECT_EQ(unique_ids.size(), 5u);
EXPECT_EQ(unique_ids[0], 2u);
EXPECT_EQ(unique_ids[1], 3u);
EXPECT_EQ(unique_ids[2], 4u);
EXPECT_EQ(unique_ids[3], 5u);
EXPECT_EQ(unique_ids[4], 6u);
}
}
}

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