Compare commits
24 Commits
7.0.1
...
jacob/wait
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50ba777fdb | ||
|
|
921d439e32 | ||
|
|
cd3fd53c8c | ||
|
|
70dfa2e778 | ||
|
|
e7e3504fcf | ||
|
|
474720511e | ||
|
|
51a4b2155e | ||
|
|
aa3a65d3ff | ||
|
|
f986ca3edc | ||
|
|
2562f715ab | ||
|
|
3ab6571593 | ||
|
|
bc8c71b63f | ||
|
|
63e79223f9 | ||
|
|
92ece94ca3 | ||
|
|
a7ec7d9243 | ||
|
|
06a4a56017 | ||
|
|
98a62f6a18 | ||
|
|
dbb4c354d6 | ||
|
|
0088e35052 | ||
|
|
3fa511a8a0 | ||
|
|
763c56481f | ||
|
|
63fdf82ebf | ||
|
|
052596c971 | ||
|
|
182ad3860e |
@@ -2,6 +2,28 @@
|
||||
Changelog for package rclcpp
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
8.2.0 (2021-03-31)
|
||||
------------------
|
||||
* Initialize integers in test_parameter_event_handler.cpp to avoid undefined behavior (`#1609 <https://github.com/ros2/rclcpp/issues/1609>`_)
|
||||
* Namespace tracetools C++ functions (`#1608 <https://github.com/ros2/rclcpp/issues/1608>`_)
|
||||
* Revert "Namespace tracetools C++ functions (`#1603 <https://github.com/ros2/rclcpp/issues/1603>`_)" (`#1607 <https://github.com/ros2/rclcpp/issues/1607>`_)
|
||||
* Namespace tracetools C++ functions (`#1603 <https://github.com/ros2/rclcpp/issues/1603>`_)
|
||||
* Clock subscription callback group spins in its own thread (`#1556 <https://github.com/ros2/rclcpp/issues/1556>`_)
|
||||
* Contributors: Chris Lalancette, Christophe Bedard, Ivan Santiago Paunovic, anaelle-sw
|
||||
|
||||
8.1.0 (2021-03-25)
|
||||
------------------
|
||||
* Remove rmw_connext_cpp references. (`#1595 <https://github.com/ros2/rclcpp/issues/1595>`_)
|
||||
* Add API for checking QoS profile compatibility (`#1554 <https://github.com/ros2/rclcpp/issues/1554>`_)
|
||||
* Document misuse of parameters callback (`#1590 <https://github.com/ros2/rclcpp/issues/1590>`_)
|
||||
* use const auto & to iterate over parameters (`#1593 <https://github.com/ros2/rclcpp/issues/1593>`_)
|
||||
* Contributors: Chris Lalancette, Jacob Perron, Karsten Knese
|
||||
|
||||
8.0.0 (2021-03-23)
|
||||
------------------
|
||||
* Guard against integer overflow in duration conversion (`#1584 <https://github.com/ros2/rclcpp/issues/1584>`_)
|
||||
* Contributors: Jacob Perron
|
||||
|
||||
7.0.1 (2021-03-22)
|
||||
------------------
|
||||
* get_parameters service should return empty if undeclared parameters are allowed (`#1514 <https://github.com/ros2/rclcpp/issues/1514>`_)
|
||||
|
||||
@@ -4,13 +4,13 @@ This document is a declaration of software quality for the `rclcpp` package, bas
|
||||
|
||||
The package `rclcpp` claims to be in the **Quality Level 1** category when it is used with a **Quality Level 1** middleware.
|
||||
|
||||
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#package-quality-categories) of the ROS2 developer guide.
|
||||
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://www.ros.org/reps/rep-2004.html) 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).
|
||||
`rclcpp` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#versioning).
|
||||
|
||||
### Version Stability [1.ii]
|
||||
|
||||
@@ -39,11 +39,11 @@ Headers under the folder `detail` are not considered part of the public API and
|
||||
|
||||
## Change Control Process [2]
|
||||
|
||||
`rclcpp` follows the recommended guidelines for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process).
|
||||
`rclcpp` follows the recommended guidelines for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process).
|
||||
|
||||
### 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.
|
||||
All changes will occur through a pull request, check [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process) for additional information.
|
||||
|
||||
### Contributor Origin [2.ii]
|
||||
|
||||
@@ -51,7 +51,7 @@ This package uses DCO as its confirmation of contributor origin policy. More inf
|
||||
|
||||
### Peer Review Policy [2.iii]
|
||||
|
||||
All pull requests will be peer-reviewed, check [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process) for additional information.
|
||||
All pull requests will be peer-reviewed, check [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process) for additional information.
|
||||
|
||||
### Continuous Integration [2.iv]
|
||||
|
||||
@@ -111,7 +111,7 @@ The tests aim to cover both typical usage and corner cases, but are quantified b
|
||||
|
||||
### Coverage [4.iii]
|
||||
|
||||
`rclcpp` follows the recommendations for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#code-coverage), and opts to use line coverage instead of branch coverage.
|
||||
`rclcpp` follows the recommendations for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#code-coverage), and opts to use line coverage instead of branch coverage.
|
||||
|
||||
This includes:
|
||||
|
||||
@@ -121,13 +121,13 @@ This includes:
|
||||
|
||||
Changes are required to make a best effort to keep or increase coverage before being accepted, but decreases are allowed if properly justified and accepted by reviewers.
|
||||
|
||||
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastCompletedBuild/cobertura/src_ros2_rclcpp_rclcpp_src_rclcpp/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://index.ros.org/doc/ros2/Contributing/ROS-2-On-boarding-Guide/#note-on-coverage-runs).
|
||||
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastCompletedBuild/cobertura/src_ros2_rclcpp_rclcpp_src_rclcpp/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#note-on-coverage-runs).
|
||||
|
||||
`rclcpp` has a line coverage `>= 95%`, which is calculated over all directories within `rclcpp` with the exception of the `experimental` directory.
|
||||
|
||||
### Performance [4.iv]
|
||||
|
||||
`rclcpp` follows the recommendations for performance testing of C/C++ code in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#performance), and opts to do performance analysis on each release rather than each change.
|
||||
`rclcpp` follows the recommendations for performance testing of C/C++ code in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#performance), and opts to do performance analysis on each release rather than each change.
|
||||
|
||||
The performance tests of `rclcpp` are located in the [test/benchmark directory](https://github.com/ros2/rclcpp/tree/master/rclcpp/test/benchmark).
|
||||
|
||||
@@ -139,7 +139,7 @@ Changes that introduce regressions in performance must be adequately justified i
|
||||
|
||||
### Linters and Static Analysis [4.v]
|
||||
|
||||
`rclcpp` uses and passes all the ROS2 standard linters and static analysis tools for a C++ package as described in the [ROS 2 Developer Guide](https://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.
|
||||
`rclcpp` uses and passes all the ROS2 standard linters and static analysis tools for a C++ package as described in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#linters-and-static-analysis). Passing implies there are no linter/static errors when testing against CI of supported platforms.
|
||||
|
||||
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/)
|
||||
|
||||
@@ -107,12 +107,12 @@ public:
|
||||
TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(this),
|
||||
get_symbol(shared_ptr_callback_));
|
||||
tracetools::get_symbol(shared_ptr_callback_));
|
||||
} else if (shared_ptr_with_request_header_callback_) {
|
||||
TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(this),
|
||||
get_symbol(shared_ptr_with_request_header_callback_));
|
||||
tracetools::get_symbol(shared_ptr_with_request_header_callback_));
|
||||
}
|
||||
#endif // TRACETOOLS_DISABLED
|
||||
}
|
||||
|
||||
@@ -243,22 +243,22 @@ public:
|
||||
TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(this),
|
||||
get_symbol(shared_ptr_callback_));
|
||||
tracetools::get_symbol(shared_ptr_callback_));
|
||||
} else if (shared_ptr_with_info_callback_) {
|
||||
TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(this),
|
||||
get_symbol(shared_ptr_with_info_callback_));
|
||||
tracetools::get_symbol(shared_ptr_with_info_callback_));
|
||||
} else if (unique_ptr_callback_) {
|
||||
TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(this),
|
||||
get_symbol(unique_ptr_callback_));
|
||||
tracetools::get_symbol(unique_ptr_callback_));
|
||||
} else if (unique_ptr_with_info_callback_) {
|
||||
TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(this),
|
||||
get_symbol(unique_ptr_with_info_callback_));
|
||||
tracetools::get_symbol(unique_ptr_with_info_callback_));
|
||||
}
|
||||
#endif // TRACETOOLS_DISABLED
|
||||
}
|
||||
|
||||
@@ -303,6 +303,13 @@ class InvalidQosOverridesException : public std::runtime_error
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
/// Thrown if a QoS compatibility check fails.
|
||||
class QoSCheckCompatibleException : public std::runtime_error
|
||||
{
|
||||
// Inherit constructors from runtime_error.
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
} // namespace exceptions
|
||||
} // namespace rclcpp
|
||||
|
||||
|
||||
@@ -840,6 +840,9 @@ public:
|
||||
*
|
||||
* This allows the node developer to control which parameters may be changed.
|
||||
*
|
||||
* It is considered bad practice to reject changes for "unknown" parameters as this prevents
|
||||
* other parts of the node (that may be aware of these parameters) from handling them.
|
||||
*
|
||||
* Note that the callback is called when declare_parameter() and its variants
|
||||
* are called, and so you cannot assume the parameter has been set before
|
||||
* this callback, so when checking a new value against the existing one, you
|
||||
|
||||
@@ -124,6 +124,13 @@ public:
|
||||
const std::string & topic_name,
|
||||
bool no_mangle = false) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
wait_for_publishers(
|
||||
const std::string & topic_name,
|
||||
size_t count,
|
||||
const std::chrono::nanoseconds & timeout) const override;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(NodeGraph)
|
||||
|
||||
|
||||
@@ -299,6 +299,29 @@ public:
|
||||
virtual
|
||||
std::vector<rclcpp::TopicEndpointInfo>
|
||||
get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle = false) const = 0;
|
||||
|
||||
/// Wait for a number of publishers to be available on a topic.
|
||||
/**
|
||||
* This function will block until the provided number of publishers are available or a timeout occurs.
|
||||
*
|
||||
* TODO(jacobperron): Detect this scenario and throw an exception
|
||||
* This function should not be called concurrently with a running GraphListener.
|
||||
* E.g. Do not call this after calling `rclcpp::GraphListener::get_graph_event()`.
|
||||
* If this happens an exception is thrown.
|
||||
*
|
||||
* \param[in] topic_name the topic to check for publishers. It will not be automatically remapped.
|
||||
* \param[in] count the number of publishers to wait for.
|
||||
* \param[in] timeout elapsed time to wait for publishers.
|
||||
* \return `true` if the number of publishers is greater than or equal to the provided count, or
|
||||
* `false` if a timeout occurs.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
bool
|
||||
wait_for_publishers(
|
||||
const std::string & topic_name,
|
||||
size_t count,
|
||||
const std::chrono::nanoseconds & timeout) const = 0;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
|
||||
@@ -48,7 +48,8 @@ public:
|
||||
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
|
||||
rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock,
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters,
|
||||
const rclcpp::QoS & qos = rclcpp::RosoutQoS()
|
||||
const rclcpp::QoS & qos = rclcpp::RosoutQoS(),
|
||||
bool use_clock_thread = true
|
||||
);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
|
||||
@@ -47,6 +47,7 @@ public:
|
||||
* - start_parameter_services = true
|
||||
* - start_parameter_event_publisher = true
|
||||
* - clock_qos = rclcpp::ClockQoS()
|
||||
* - use_clock_thread = true
|
||||
* - rosout_qos = rclcpp::RosoutQoS()
|
||||
* - parameter_event_qos = rclcpp::ParameterEventQoS
|
||||
* - with history setting and depth from rmw_qos_profile_parameter_events
|
||||
@@ -258,6 +259,20 @@ public:
|
||||
NodeOptions &
|
||||
clock_qos(const rclcpp::QoS & clock_qos);
|
||||
|
||||
|
||||
/// Return the use_clock_thread flag.
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
use_clock_thread() const;
|
||||
|
||||
/// Set the use_clock_thread flag, return this for parameter idiom.
|
||||
/**
|
||||
* If true, a dedicated thread will be used to subscribe to "/clock" topic.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
NodeOptions &
|
||||
use_clock_thread(bool use_clock_thread);
|
||||
|
||||
/// Return a reference to the parameter_event_qos QoS.
|
||||
RCLCPP_PUBLIC
|
||||
const rclcpp::QoS &
|
||||
@@ -384,6 +399,8 @@ private:
|
||||
|
||||
rclcpp::QoS clock_qos_ = rclcpp::ClockQoS();
|
||||
|
||||
bool use_clock_thread_ {true};
|
||||
|
||||
rclcpp::QoS parameter_event_qos_ = rclcpp::ParameterEventsQoS(
|
||||
rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events)
|
||||
);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "rclcpp/duration.hpp"
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
#include "rcl/logging_rosout.h"
|
||||
#include "rmw/incompatible_qos_events_statuses.h"
|
||||
@@ -62,6 +63,13 @@ enum class LivelinessPolicy
|
||||
Unknown = RMW_QOS_POLICY_LIVELINESS_UNKNOWN,
|
||||
};
|
||||
|
||||
enum class QoSCompatibility
|
||||
{
|
||||
Ok = RMW_QOS_COMPATIBILITY_OK,
|
||||
Warning = RMW_QOS_COMPATIBILITY_WARNING,
|
||||
Error = RMW_QOS_COMPATIBILITY_ERROR,
|
||||
};
|
||||
|
||||
/// QoS initialization values, cannot be created directly, use KeepAll or KeepLast instead.
|
||||
struct RCLCPP_PUBLIC QoSInitialization
|
||||
{
|
||||
@@ -273,6 +281,61 @@ bool operator==(const QoS & left, const QoS & right);
|
||||
RCLCPP_PUBLIC
|
||||
bool operator!=(const QoS & left, const QoS & right);
|
||||
|
||||
/// Result type for checking QoS compatibility
|
||||
/**
|
||||
* \see rclcpp::qos_check_compatible()
|
||||
*/
|
||||
struct QoSCheckCompatibleResult
|
||||
{
|
||||
/// Compatibility result.
|
||||
QoSCompatibility compatibility;
|
||||
|
||||
/// Reason for a (possible) incompatibility.
|
||||
/**
|
||||
* Set if compatiblity is QoSCompatibility::Warning or QoSCompatiblity::Error.
|
||||
* Not set if the QoS profiles are compatible.
|
||||
*/
|
||||
std::string reason;
|
||||
};
|
||||
|
||||
/// Check if two QoS profiles are compatible.
|
||||
/**
|
||||
* Two QoS profiles are compatible if a publisher and subcription
|
||||
* using the QoS policies can communicate with each other.
|
||||
*
|
||||
* If any policies have value "system default" or "unknown" then it is possible that
|
||||
* compatiblity cannot be determined.
|
||||
* In this case, the value QoSCompatility::Warning is set as part of
|
||||
* the returned structure.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* ```cpp
|
||||
* rclcpp::QoSCheckCompatibleResult result = rclcpp::qos_check_compatible(
|
||||
* publisher_qos, subscription_qos);
|
||||
* if (rclcpp::QoSCompatibility::Error != result.compatibility) {
|
||||
* // QoS not compatible ...
|
||||
* // result.reason contains info about the incompatibility
|
||||
* } else if (rclcpp::QoSCompatibility::Warning != result.compatibility) {
|
||||
* // QoS may not be compatible ...
|
||||
* // result.reason contains info about the possible incompatibility
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* \param[in] publisher_qos: The QoS profile for a publisher.
|
||||
* \param[in] subscription_qos: The QoS profile for a subscription.
|
||||
* \return Struct with compatiblity set to QoSCompatibility::Ok if the QoS profiles are
|
||||
* compatible, or
|
||||
* \return Struct with compatibility set to QoSCompatibility::Warning if there is a chance
|
||||
* the QoS profiles are not compatible, or
|
||||
* \return Struct with compatibility set to QoSCompatibility::Error if the QoS profiles are
|
||||
* not compatible.
|
||||
* \throws rclcpp::exceptions::QoSCheckCompatibilityException if an unexpected error occurs.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
QoSCheckCompatibleResult
|
||||
qos_check_compatible(const QoS & publisher_qos, const QoS & subscription_qos);
|
||||
|
||||
/**
|
||||
* Clock QoS class
|
||||
* - History: Keep last,
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "rcl_interfaces/msg/parameter_event.hpp"
|
||||
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/executors.hpp"
|
||||
#include "rclcpp/node_interfaces/node_parameters_interface.hpp"
|
||||
|
||||
|
||||
@@ -57,7 +58,10 @@ public:
|
||||
* \param qos QoS that will be used when creating a `/clock` subscription.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
explicit TimeSource(rclcpp::Node::SharedPtr node, const rclcpp::QoS & qos = rclcpp::ClockQoS());
|
||||
explicit TimeSource(
|
||||
rclcpp::Node::SharedPtr node,
|
||||
const rclcpp::QoS & qos = rclcpp::ClockQoS(),
|
||||
bool use_clock_thread = true);
|
||||
|
||||
/// Empty constructor
|
||||
/**
|
||||
@@ -66,7 +70,9 @@ public:
|
||||
* \param qos QoS that will be used when creating a `/clock` subscription.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
explicit TimeSource(const rclcpp::QoS & qos = rclcpp::ClockQoS());
|
||||
explicit TimeSource(
|
||||
const rclcpp::QoS & qos = rclcpp::ClockQoS(),
|
||||
bool use_clock_thread = true);
|
||||
|
||||
/// Attack node to the time source.
|
||||
/**
|
||||
@@ -118,6 +124,11 @@ public:
|
||||
RCLCPP_PUBLIC
|
||||
~TimeSource();
|
||||
|
||||
protected:
|
||||
// Dedicated thread for clock subscription.
|
||||
bool use_clock_thread_;
|
||||
std::thread clock_executor_thread_;
|
||||
|
||||
private:
|
||||
// Preserve the node reference
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_;
|
||||
@@ -140,6 +151,9 @@ private:
|
||||
using SubscriptionT = rclcpp::Subscription<MessageT, Alloc>;
|
||||
std::shared_ptr<SubscriptionT> clock_subscription_{nullptr};
|
||||
std::mutex clock_sub_lock_;
|
||||
rclcpp::CallbackGroup::SharedPtr clock_callback_group_;
|
||||
rclcpp::executors::SingleThreadedExecutor::SharedPtr clock_executor_;
|
||||
std::promise<void> cancel_clock_executor_promise_;
|
||||
|
||||
// The clock callback itself
|
||||
void clock_cb(const rosgraph_msgs::msg::Clock::SharedPtr msg);
|
||||
|
||||
@@ -181,7 +181,7 @@ public:
|
||||
TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(&callback_),
|
||||
get_symbol(callback_));
|
||||
tracetools::get_symbol(callback_));
|
||||
}
|
||||
|
||||
/// Default destructor.
|
||||
|
||||
@@ -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>7.0.1</version>
|
||||
<version>8.2.0</version>
|
||||
<description>The ROS client library in C++.</description>
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
<maintainer email="mabel@openrobotics.org">Mabel Zhang</maintainer>
|
||||
|
||||
@@ -67,13 +67,27 @@ Duration::operator builtin_interfaces::msg::Duration() const
|
||||
{
|
||||
builtin_interfaces::msg::Duration msg_duration;
|
||||
constexpr rcl_duration_value_t kDivisor = RCL_S_TO_NS(1);
|
||||
constexpr int32_t max_s = std::numeric_limits<int32_t>::max();
|
||||
constexpr int32_t min_s = std::numeric_limits<int32_t>::min();
|
||||
constexpr uint32_t max_ns = std::numeric_limits<uint32_t>::max();
|
||||
const auto result = std::div(rcl_duration_.nanoseconds, kDivisor);
|
||||
if (result.rem >= 0) {
|
||||
msg_duration.sec = static_cast<std::int32_t>(result.quot);
|
||||
msg_duration.nanosec = static_cast<std::uint32_t>(result.rem);
|
||||
// saturate if we will overflow
|
||||
if (result.quot > max_s) {
|
||||
msg_duration.sec = max_s;
|
||||
msg_duration.nanosec = max_ns;
|
||||
} else {
|
||||
msg_duration.sec = static_cast<int32_t>(result.quot);
|
||||
msg_duration.nanosec = static_cast<uint32_t>(result.rem);
|
||||
}
|
||||
} else {
|
||||
msg_duration.sec = static_cast<std::int32_t>(result.quot - 1);
|
||||
msg_duration.nanosec = static_cast<std::uint32_t>(kDivisor + result.rem);
|
||||
if (result.quot <= min_s) {
|
||||
msg_duration.sec = min_s;
|
||||
msg_duration.nanosec = 0u;
|
||||
} else {
|
||||
msg_duration.sec = static_cast<int32_t>(result.quot - 1);
|
||||
msg_duration.nanosec = static_cast<uint32_t>(kDivisor + result.rem);
|
||||
}
|
||||
}
|
||||
return msg_duration;
|
||||
}
|
||||
@@ -238,11 +252,14 @@ Duration::to_rmw_time() const
|
||||
throw std::runtime_error("rmw_time_t cannot be negative");
|
||||
}
|
||||
|
||||
// reuse conversion logic from msg creation
|
||||
builtin_interfaces::msg::Duration msg = *this;
|
||||
// Purposefully avoid creating from builtin_interfaces::msg::Duration
|
||||
// to avoid possible overflow converting from int64_t to int32_t, then back to uint64_t
|
||||
rmw_time_t result;
|
||||
result.sec = static_cast<uint64_t>(msg.sec);
|
||||
result.nsec = static_cast<uint64_t>(msg.nanosec);
|
||||
constexpr rcl_duration_value_t kDivisor = RCL_S_TO_NS(1);
|
||||
const auto div_result = std::div(rcl_duration_.nanoseconds, kDivisor);
|
||||
result.sec = static_cast<uint64_t>(div_result.quot);
|
||||
result.nsec = static_cast<uint64_t>(div_result.rem);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -187,7 +187,8 @@ Node::Node(
|
||||
node_logging_,
|
||||
node_clock_,
|
||||
node_parameters_,
|
||||
options.clock_qos()
|
||||
options.clock_qos(),
|
||||
options.use_clock_thread()
|
||||
)),
|
||||
node_waitables_(new rclcpp::node_interfaces::NodeWaitables(node_base_.get())),
|
||||
node_options_(options),
|
||||
|
||||
@@ -533,6 +533,31 @@ NodeGraph::get_subscriptions_info_by_topic(
|
||||
rcl_get_subscriptions_info_by_topic);
|
||||
}
|
||||
|
||||
bool
|
||||
NodeGraph::wait_for_publishers(
|
||||
const std::string & topic_name,
|
||||
size_t count,
|
||||
const std::chrono::nanoseconds & timeout) const
|
||||
{
|
||||
// TODO(jacobperron): Guard against concurrent use of graph guard condition
|
||||
// (e.g. with GraphListener)
|
||||
// rcl_wait_for_publishers() also uses the graph guard condition
|
||||
auto rcl_node_handle = node_base_->get_rcl_node_handle();
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator();
|
||||
bool success = false;
|
||||
rcl_ret_t ret = rcl_wait_for_publishers(
|
||||
rcl_node_handle,
|
||||
&allocator,
|
||||
topic_name.c_str(),
|
||||
count,
|
||||
timeout.count(),
|
||||
&success);
|
||||
if (ret != RCL_RET_OK && ret != RCL_RET_TIMEOUT) {
|
||||
throw_from_rcl_error(ret, "error while waiting for publishers");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
std::string &
|
||||
rclcpp::TopicEndpointInfo::node_name()
|
||||
{
|
||||
|
||||
@@ -27,7 +27,8 @@ NodeTimeSource::NodeTimeSource(
|
||||
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
|
||||
rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock,
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters,
|
||||
const rclcpp::QoS & qos)
|
||||
const rclcpp::QoS & qos,
|
||||
bool use_clock_thread)
|
||||
: node_base_(node_base),
|
||||
node_topics_(node_topics),
|
||||
node_graph_(node_graph),
|
||||
@@ -35,7 +36,7 @@ NodeTimeSource::NodeTimeSource(
|
||||
node_logging_(node_logging),
|
||||
node_clock_(node_clock),
|
||||
node_parameters_(node_parameters),
|
||||
time_source_(qos)
|
||||
time_source_(qos, use_clock_thread)
|
||||
{
|
||||
time_source_.attachNode(
|
||||
node_base_,
|
||||
|
||||
@@ -78,6 +78,7 @@ NodeOptions::operator=(const NodeOptions & other)
|
||||
this->start_parameter_services_ = other.start_parameter_services_;
|
||||
this->start_parameter_event_publisher_ = other.start_parameter_event_publisher_;
|
||||
this->clock_qos_ = other.clock_qos_;
|
||||
this->use_clock_thread_ = other.use_clock_thread_;
|
||||
this->parameter_event_qos_ = other.parameter_event_qos_;
|
||||
this->rosout_qos_ = other.rosout_qos_;
|
||||
this->parameter_event_publisher_options_ = other.parameter_event_publisher_options_;
|
||||
@@ -272,6 +273,19 @@ NodeOptions::clock_qos(const rclcpp::QoS & clock_qos)
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
NodeOptions::use_clock_thread() const
|
||||
{
|
||||
return this->use_clock_thread_;
|
||||
}
|
||||
|
||||
NodeOptions &
|
||||
NodeOptions::use_clock_thread(bool use_clock_thread)
|
||||
{
|
||||
this->use_clock_thread_ = use_clock_thread;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const rclcpp::QoS &
|
||||
NodeOptions::parameter_event_qos() const
|
||||
{
|
||||
|
||||
@@ -43,7 +43,7 @@ ParameterService::ParameterService(
|
||||
{
|
||||
try {
|
||||
auto parameters = node_params->get_parameters(request->names);
|
||||
for (const auto param : parameters) {
|
||||
for (const auto & param : parameters) {
|
||||
response->values.push_back(param.get_value_message());
|
||||
}
|
||||
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "rmw/error_handling.h"
|
||||
#include "rmw/types.h"
|
||||
#include "rmw/qos_profiles.h"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
@@ -309,6 +311,45 @@ bool operator!=(const QoS & left, const QoS & right)
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
QoSCheckCompatibleResult
|
||||
qos_check_compatible(const QoS & publisher_qos, const QoS & subscription_qos)
|
||||
{
|
||||
rmw_qos_compatibility_type_t compatible;
|
||||
const size_t reason_size = 2048u;
|
||||
char reason_c_str[reason_size] = "";
|
||||
rmw_ret_t ret = rmw_qos_profile_check_compatible(
|
||||
publisher_qos.get_rmw_qos_profile(),
|
||||
subscription_qos.get_rmw_qos_profile(),
|
||||
&compatible,
|
||||
reason_c_str,
|
||||
reason_size);
|
||||
if (RMW_RET_OK != ret) {
|
||||
std::string error_str(rmw_get_error_string().str);
|
||||
rmw_reset_error();
|
||||
throw rclcpp::exceptions::QoSCheckCompatibleException{error_str};
|
||||
}
|
||||
|
||||
QoSCheckCompatibleResult result;
|
||||
result.reason = std::string(reason_c_str);
|
||||
|
||||
switch (compatible) {
|
||||
case RMW_QOS_COMPATIBILITY_OK:
|
||||
result.compatibility = QoSCompatibility::Ok;
|
||||
break;
|
||||
case RMW_QOS_COMPATIBILITY_WARNING:
|
||||
result.compatibility = QoSCompatibility::Warning;
|
||||
break;
|
||||
case RMW_QOS_COMPATIBILITY_ERROR:
|
||||
result.compatibility = QoSCompatibility::Error;
|
||||
break;
|
||||
default:
|
||||
throw rclcpp::exceptions::QoSCheckCompatibleException{
|
||||
"Unexpected compatibility value returned by rmw '" + std::to_string(compatible) +
|
||||
"'"};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ClockQoS::ClockQoS(const QoSInitialization & qos_initialization)
|
||||
// Using `rmw_qos_profile_sensor_data` intentionally.
|
||||
// It's best effort and `qos_initialization` is overriding the depth to 1.
|
||||
|
||||
@@ -33,21 +33,29 @@
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
TimeSource::TimeSource(std::shared_ptr<rclcpp::Node> node, const rclcpp::QoS & qos)
|
||||
: logger_(rclcpp::get_logger("rclcpp")),
|
||||
TimeSource::TimeSource(
|
||||
std::shared_ptr<rclcpp::Node> node,
|
||||
const rclcpp::QoS & qos,
|
||||
bool use_clock_thread)
|
||||
: use_clock_thread_(use_clock_thread),
|
||||
logger_(rclcpp::get_logger("rclcpp")),
|
||||
qos_(qos)
|
||||
{
|
||||
this->attachNode(node);
|
||||
}
|
||||
|
||||
TimeSource::TimeSource(const rclcpp::QoS & qos)
|
||||
: logger_(rclcpp::get_logger("rclcpp")),
|
||||
TimeSource::TimeSource(
|
||||
const rclcpp::QoS & qos,
|
||||
bool use_clock_thread)
|
||||
: use_clock_thread_(use_clock_thread),
|
||||
logger_(rclcpp::get_logger("rclcpp")),
|
||||
qos_(qos)
|
||||
{
|
||||
}
|
||||
|
||||
void TimeSource::attachNode(rclcpp::Node::SharedPtr node)
|
||||
{
|
||||
use_clock_thread_ = node->get_node_options().use_clock_thread();
|
||||
attachNode(
|
||||
node->get_node_base_interface(),
|
||||
node->get_node_topics_interface(),
|
||||
@@ -127,7 +135,7 @@ void TimeSource::attachNode(
|
||||
void TimeSource::detachNode()
|
||||
{
|
||||
this->ros_time_active_ = false;
|
||||
clock_subscription_.reset();
|
||||
destroy_clock_sub();
|
||||
parameter_subscription_.reset();
|
||||
node_base_.reset();
|
||||
node_topics_.reset();
|
||||
@@ -242,6 +250,28 @@ void TimeSource::create_clock_sub()
|
||||
rclcpp::QosPolicyKind::Reliability,
|
||||
});
|
||||
|
||||
if (use_clock_thread_) {
|
||||
clock_callback_group_ = node_base_->create_callback_group(
|
||||
rclcpp::CallbackGroupType::MutuallyExclusive,
|
||||
false
|
||||
);
|
||||
options.callback_group = clock_callback_group_;
|
||||
rclcpp::ExecutorOptions exec_options;
|
||||
exec_options.context = node_base_->get_context();
|
||||
clock_executor_ =
|
||||
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(exec_options);
|
||||
if (!clock_executor_thread_.joinable()) {
|
||||
clock_executor_thread_ = std::thread(
|
||||
[this]() {
|
||||
cancel_clock_executor_promise_ = std::promise<void>{};
|
||||
auto future = cancel_clock_executor_promise_.get_future();
|
||||
clock_executor_->add_callback_group(clock_callback_group_, node_base_);
|
||||
clock_executor_->spin_until_future_complete(future);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
clock_subscription_ = rclcpp::create_subscription<rosgraph_msgs::msg::Clock>(
|
||||
node_parameters_,
|
||||
node_topics_,
|
||||
@@ -255,6 +285,12 @@ void TimeSource::create_clock_sub()
|
||||
void TimeSource::destroy_clock_sub()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(clock_sub_lock_);
|
||||
if (clock_executor_thread_.joinable()) {
|
||||
cancel_clock_executor_promise_.set_value();
|
||||
clock_executor_->cancel();
|
||||
clock_executor_thread_.join();
|
||||
clock_executor_->remove_callback_group(clock_callback_group_);
|
||||
}
|
||||
clock_subscription_.reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ TEST_F(TestStaticExecutorEntitiesCollector, add_remove_node_with_entities) {
|
||||
auto client = node->create_client<test_msgs::srv::Empty>("service");
|
||||
auto waitable = std::make_shared<TestWaitable>();
|
||||
|
||||
// Adding a subscription with rmw_connext_cpp adds another waitable, so we need to get the
|
||||
// Adding a subscription could add another waitable, so we need to get the
|
||||
// current number of waitables just before adding the new waitable.
|
||||
expected_number_of_entities->waitables = get_number_of_default_entities(node)->waitables;
|
||||
node->get_node_waitables_interface()->add_waitable(waitable, nullptr);
|
||||
|
||||
@@ -511,10 +511,7 @@ TEST_F(TestAllocatorMemoryStrategy, number_of_entities_with_subscription) {
|
||||
RclWaitSetSizes expected_sizes = {};
|
||||
expected_sizes.size_of_subscriptions = 1;
|
||||
const std::string implementation_identifier = rmw_get_implementation_identifier();
|
||||
// TODO(asorbini): Remove Connext exception once ros2/rmw_connext is deprecated.
|
||||
if (implementation_identifier == "rmw_connext_cpp" ||
|
||||
implementation_identifier == "rmw_cyclonedds_cpp")
|
||||
{
|
||||
if (implementation_identifier == "rmw_cyclonedds_cpp") {
|
||||
// For cyclonedds, a subscription will also add an event and waitable
|
||||
expected_sizes.size_of_events += 1;
|
||||
expected_sizes.size_of_waitables += 1;
|
||||
|
||||
@@ -138,6 +138,7 @@ TEST_F(TestDuration, maximum_duration) {
|
||||
static const int64_t HALF_SEC_IN_NS = 500 * 1000 * 1000;
|
||||
static const int64_t ONE_SEC_IN_NS = 1000 * 1000 * 1000;
|
||||
static const int64_t ONE_AND_HALF_SEC_IN_NS = 3 * HALF_SEC_IN_NS;
|
||||
static const int64_t MAX_NANOSECONDS = std::numeric_limits<int64_t>::max();
|
||||
|
||||
TEST_F(TestDuration, from_seconds) {
|
||||
EXPECT_EQ(rclcpp::Duration(0ns), rclcpp::Duration::from_seconds(0.0));
|
||||
@@ -267,6 +268,34 @@ TEST_F(TestDuration, conversions) {
|
||||
auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
|
||||
EXPECT_EQ(chrono_duration.count(), -ONE_AND_HALF_SEC_IN_NS);
|
||||
}
|
||||
|
||||
{
|
||||
auto duration = rclcpp::Duration::from_nanoseconds(MAX_NANOSECONDS);
|
||||
|
||||
const auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
|
||||
EXPECT_EQ(duration_msg.sec, std::numeric_limits<int32_t>::max());
|
||||
EXPECT_EQ(duration_msg.nanosec, std::numeric_limits<uint32_t>::max());
|
||||
|
||||
auto rmw_time = duration.to_rmw_time();
|
||||
EXPECT_EQ(rmw_time.sec, 9223372036u);
|
||||
EXPECT_EQ(rmw_time.nsec, 854775807u);
|
||||
|
||||
auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
|
||||
EXPECT_EQ(chrono_duration.count(), MAX_NANOSECONDS);
|
||||
}
|
||||
|
||||
{
|
||||
auto duration = rclcpp::Duration::from_nanoseconds(-MAX_NANOSECONDS);
|
||||
|
||||
const auto duration_msg = static_cast<builtin_interfaces::msg::Duration>(duration);
|
||||
EXPECT_EQ(duration_msg.sec, std::numeric_limits<int32_t>::min());
|
||||
EXPECT_EQ(duration_msg.nanosec, 0u);
|
||||
|
||||
EXPECT_THROW(duration.to_rmw_time(), std::runtime_error);
|
||||
|
||||
auto chrono_duration = duration.to_chrono<std::chrono::nanoseconds>();
|
||||
EXPECT_EQ(chrono_duration.count(), -MAX_NANOSECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestDuration, test_some_constructors) {
|
||||
|
||||
@@ -149,8 +149,8 @@ TEST_F(TestNode, RegisterParameterCallback)
|
||||
|
||||
TEST_F(TestNode, SameParameterDifferentNode)
|
||||
{
|
||||
int64_t int_param_node1;
|
||||
int64_t int_param_node2;
|
||||
int64_t int_param_node1{0};
|
||||
int64_t int_param_node2{0};
|
||||
|
||||
auto cb1 = [&int_param_node1](const rclcpp::Parameter & p) {
|
||||
int_param_node1 = p.get_value<int64_t>();
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "rclcpp/qos.hpp"
|
||||
|
||||
#include "rmw/types.h"
|
||||
@@ -208,3 +210,43 @@ TEST(TestQoS, policy_name_from_kind) {
|
||||
"LIFESPAN_QOS_POLICY",
|
||||
rclcpp::qos_policy_name_from_kind(RMW_QOS_POLICY_LIFESPAN));
|
||||
}
|
||||
|
||||
TEST(TestQoS, qos_check_compatible)
|
||||
{
|
||||
// Compatible
|
||||
{
|
||||
rclcpp::QoS qos = rclcpp::QoS(1)
|
||||
.reliable()
|
||||
.durability_volatile()
|
||||
.deadline(rclcpp::Duration(1, 0u))
|
||||
.lifespan(rclcpp::Duration(1, 0u))
|
||||
.liveliness(rclcpp::LivelinessPolicy::Automatic)
|
||||
.liveliness_lease_duration(rclcpp::Duration(1, 0u));
|
||||
rclcpp::QoSCheckCompatibleResult ret = rclcpp::qos_check_compatible(qos, qos);
|
||||
EXPECT_EQ(ret.compatibility, rclcpp::QoSCompatibility::Ok);
|
||||
EXPECT_EQ(ret.reason, std::string(""));
|
||||
}
|
||||
|
||||
// Note, the following incompatible tests assume we are using a DDS middleware,
|
||||
// and may not be valid for other RMWs.
|
||||
// TODO(jacobperron): programmatically check if current RMW is one of the officially
|
||||
// supported DDS middlewares before running the following tests
|
||||
|
||||
// Incompatible
|
||||
{
|
||||
rclcpp::QoS pub_qos = rclcpp::QoS(1).best_effort();
|
||||
rclcpp::QoS sub_qos = rclcpp::QoS(1).reliable();
|
||||
rclcpp::QoSCheckCompatibleResult ret = rclcpp::qos_check_compatible(pub_qos, sub_qos);
|
||||
EXPECT_EQ(ret.compatibility, rclcpp::QoSCompatibility::Error);
|
||||
EXPECT_FALSE(ret.reason.empty());
|
||||
}
|
||||
|
||||
// Warn of possible incompatibility
|
||||
{
|
||||
rclcpp::SystemDefaultsQoS pub_qos;
|
||||
rclcpp::QoS sub_qos = rclcpp::QoS(1).reliable();
|
||||
rclcpp::QoSCheckCompatibleResult ret = rclcpp::qos_check_compatible(pub_qos, sub_qos);
|
||||
EXPECT_EQ(ret.compatibility, rclcpp::QoSCompatibility::Warning);
|
||||
EXPECT_FALSE(ret.reason.empty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,3 +516,229 @@ TEST_F(TestTimeSource, no_pre_jump_callback) {
|
||||
EXPECT_EQ(1, cbo.last_postcallback_id_);
|
||||
EXPECT_EQ(1, cbo.post_callback_calls_);
|
||||
}
|
||||
|
||||
// A TimeSource-inheriting class
|
||||
// that allows access to TimeSource protected attributes
|
||||
// use_clock_thread_ and clock_executor_thread_
|
||||
class ClockThreadTestingTimeSource : public rclcpp::TimeSource
|
||||
{
|
||||
public:
|
||||
ClockThreadTestingTimeSource()
|
||||
: rclcpp::TimeSource()
|
||||
{
|
||||
}
|
||||
|
||||
bool GetUseClockThreadOption()
|
||||
{
|
||||
return this->use_clock_thread_;
|
||||
}
|
||||
|
||||
bool IsClockThreadJoinable()
|
||||
{
|
||||
return this->clock_executor_thread_.joinable();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TestTimeSource, check_use_clock_thread_value) {
|
||||
// Create three nodes, with use_clock_thread option
|
||||
// respectively set to default, true, and false
|
||||
|
||||
auto default_node_ = std::make_shared<rclcpp::Node>(
|
||||
"default_option_node");
|
||||
|
||||
auto clock_thread_node_ = std::make_shared<rclcpp::Node>(
|
||||
"clock_thread_node",
|
||||
rclcpp::NodeOptions().use_clock_thread(true));
|
||||
|
||||
auto no_clock_thread_node_ = std::make_shared<rclcpp::Node>(
|
||||
"no_clock_thread_node",
|
||||
rclcpp::NodeOptions().use_clock_thread(false));
|
||||
|
||||
// Test value of use_clock_thread_ TimeSource attribute
|
||||
// when the different nodes are attached
|
||||
|
||||
ClockThreadTestingTimeSource ts;
|
||||
|
||||
ts.attachNode(default_node_);
|
||||
ASSERT_TRUE(ts.GetUseClockThreadOption());
|
||||
ts.detachNode();
|
||||
|
||||
ts.attachNode(clock_thread_node_);
|
||||
ASSERT_TRUE(ts.GetUseClockThreadOption());
|
||||
ts.detachNode();
|
||||
|
||||
ts.attachNode(no_clock_thread_node_);
|
||||
ASSERT_FALSE(ts.GetUseClockThreadOption());
|
||||
ts.detachNode();
|
||||
}
|
||||
|
||||
TEST_F(TestTimeSource, check_clock_thread_status) {
|
||||
// Test if TimeSource clock-dedicated thread is running
|
||||
// according to the use_sim_time parameter
|
||||
// and to the options of the attached node
|
||||
ClockThreadTestingTimeSource ts;
|
||||
|
||||
// Tests for default options node
|
||||
auto default_node_ = std::make_shared<rclcpp::Node>(
|
||||
"default_option_node");
|
||||
|
||||
default_node_->set_parameter(rclcpp::Parameter("use_sim_time", true));
|
||||
ts.attachNode(default_node_);
|
||||
ASSERT_TRUE(ts.IsClockThreadJoinable());
|
||||
ts.detachNode();
|
||||
|
||||
default_node_->set_parameter(rclcpp::Parameter("use_sim_time", false));
|
||||
ts.attachNode(default_node_);
|
||||
ASSERT_FALSE(ts.IsClockThreadJoinable());
|
||||
ts.detachNode();
|
||||
|
||||
// Tests for node with use_clock_thread option forced to false
|
||||
auto no_clock_thread_node_ = std::make_shared<rclcpp::Node>(
|
||||
"no_clock_thread_node",
|
||||
rclcpp::NodeOptions().use_clock_thread(false));
|
||||
|
||||
no_clock_thread_node_->set_parameter(rclcpp::Parameter("use_sim_time", true));
|
||||
ts.attachNode(no_clock_thread_node_);
|
||||
ASSERT_FALSE(ts.IsClockThreadJoinable());
|
||||
ts.detachNode();
|
||||
|
||||
no_clock_thread_node_->set_parameter(rclcpp::Parameter("use_sim_time", false));
|
||||
ts.attachNode(no_clock_thread_node_);
|
||||
ASSERT_FALSE(ts.IsClockThreadJoinable());
|
||||
ts.detachNode();
|
||||
}
|
||||
|
||||
// A Node-inheriting class
|
||||
// that regularly publishes a incremented Clock msg on topic `/clock'
|
||||
class SimClockPublisherNode : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
SimClockPublisherNode()
|
||||
: rclcpp::Node("sim_clock_publisher_node")
|
||||
{
|
||||
// Create a clock publisher
|
||||
clock_pub_ = this->create_publisher<rosgraph_msgs::msg::Clock>(
|
||||
"/clock",
|
||||
rclcpp::QoS(1)
|
||||
);
|
||||
|
||||
// Create a 1ms timer
|
||||
pub_timer_ = this->create_wall_timer(
|
||||
std::chrono::milliseconds(1),
|
||||
std::bind(
|
||||
&SimClockPublisherNode::timer_callback,
|
||||
this)
|
||||
);
|
||||
|
||||
// Init clock msg to zero
|
||||
clock_msg_.clock.sec = 0;
|
||||
clock_msg_.clock.nanosec = 0;
|
||||
}
|
||||
|
||||
~SimClockPublisherNode()
|
||||
{
|
||||
// Cleanly stop executor and thread
|
||||
node_executor.cancel();
|
||||
node_thread_.join();
|
||||
}
|
||||
|
||||
void SpinNode()
|
||||
{
|
||||
// Spin node in its own dedicated thread
|
||||
node_thread_ = std::thread(
|
||||
[this]() {
|
||||
node_executor.add_node(this->get_node_base_interface());
|
||||
node_executor.spin();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
void timer_callback()
|
||||
{
|
||||
// Increment clock msg and publish it
|
||||
clock_msg_.clock.nanosec += 1000000;
|
||||
clock_pub_->publish(clock_msg_);
|
||||
}
|
||||
|
||||
rclcpp::Publisher<rosgraph_msgs::msg::Clock>::SharedPtr clock_pub_;
|
||||
rclcpp::TimerBase::SharedPtr pub_timer_;
|
||||
rosgraph_msgs::msg::Clock clock_msg_;
|
||||
std::thread node_thread_;
|
||||
rclcpp::executors::SingleThreadedExecutor node_executor;
|
||||
};
|
||||
|
||||
// A Node-inheriting class
|
||||
// that check its clock time within a timer callback
|
||||
class ClockThreadTestingNode : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
ClockThreadTestingNode()
|
||||
: rclcpp::Node("clock_thread_testing_node")
|
||||
{
|
||||
// Set use_sim_time parameter to true to subscribe to `/clock` topic
|
||||
this->set_parameter(rclcpp::Parameter("use_sim_time", true));
|
||||
|
||||
// Create a 100ms timer
|
||||
timer_ = this->create_wall_timer(
|
||||
std::chrono::milliseconds(100),
|
||||
std::bind(
|
||||
&ClockThreadTestingNode::timer_callback,
|
||||
this)
|
||||
);
|
||||
}
|
||||
|
||||
bool GetIsCallbackFrozen()
|
||||
{
|
||||
return is_callback_frozen_;
|
||||
}
|
||||
|
||||
private:
|
||||
void timer_callback()
|
||||
{
|
||||
rclcpp::Time start_time = this->now();
|
||||
bool is_time_out = false;
|
||||
|
||||
// While loop condition tests
|
||||
// if the node's clock time is incremented
|
||||
while (rclcpp::ok() &&
|
||||
!is_time_out)
|
||||
{
|
||||
rclcpp::sleep_for(std::chrono::milliseconds(100));
|
||||
rclcpp::Time time_now = this->now();
|
||||
rclcpp::Duration time_spent = time_now - start_time;
|
||||
is_time_out = time_spent.seconds() > 1.0;
|
||||
}
|
||||
|
||||
// If out of while loop, set variable to false
|
||||
// and cancel timer to avoid to enter the callback again
|
||||
is_callback_frozen_ = false;
|
||||
timer_->cancel();
|
||||
}
|
||||
|
||||
rclcpp::TimerBase::SharedPtr timer_;
|
||||
bool is_callback_frozen_ = true;
|
||||
};
|
||||
|
||||
TEST_F(TestTimeSource, check_sim_time_updated_in_callback_if_use_clock_thread) {
|
||||
// Test if clock time of a node with
|
||||
// parameter use_sim_time = true and option use_clock_thread = true
|
||||
// is updated while node is not spinning
|
||||
// (in a timer callback)
|
||||
|
||||
// Create a "sim time" publisher and spin it
|
||||
SimClockPublisherNode pub_node;
|
||||
pub_node.SpinNode();
|
||||
|
||||
// Spin node for 2 seconds
|
||||
ClockThreadTestingNode clock_thread_testing_node;
|
||||
auto steady_clock = rclcpp::Clock(RCL_STEADY_TIME);
|
||||
auto start_time = steady_clock.now();
|
||||
while (rclcpp::ok() &&
|
||||
(steady_clock.now() - start_time).seconds() < 2.0)
|
||||
{
|
||||
rclcpp::spin_some(clock_thread_testing_node.get_node_base_interface());
|
||||
}
|
||||
|
||||
// Node should have get out of timer callback
|
||||
ASSERT_FALSE(clock_thread_testing_node.GetIsCallbackFrozen());
|
||||
}
|
||||
|
||||
@@ -3,6 +3,15 @@ Changelog for package rclcpp_action
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
8.2.0 (2021-03-31)
|
||||
------------------
|
||||
|
||||
8.1.0 (2021-03-25)
|
||||
------------------
|
||||
|
||||
8.0.0 (2021-03-23)
|
||||
------------------
|
||||
|
||||
7.0.1 (2021-03-22)
|
||||
------------------
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ This document is a declaration of software quality for the `rclcpp_action` packa
|
||||
|
||||
The package `rclcpp_action` claims to be in the **Quality Level 1** category when it is used with a **Quality Level 1** middleware.
|
||||
|
||||
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#package-quality-categories) of the ROS2 developer guide.
|
||||
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://www.ros.org/reps/rep-2004.html) 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).
|
||||
`rclcpp_action` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#versioning).
|
||||
|
||||
### Version Stability [1.ii]
|
||||
|
||||
@@ -37,11 +37,11 @@ All installed headers are in the `include` directory of the package, headers in
|
||||
|
||||
## 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).
|
||||
`rclcpp_action` follows the recommended guidelines for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process).
|
||||
|
||||
### 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.
|
||||
All changes will occur through a pull request, check [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process) for additional information.
|
||||
|
||||
### Contributor Origin [2.ii]
|
||||
|
||||
@@ -49,7 +49,7 @@ This package uses DCO as its confirmation of contributor origin policy. More inf
|
||||
|
||||
### Peer Review Policy [2.iii]
|
||||
|
||||
All pull requests will be peer-reviewed, check [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process) for additional information.
|
||||
All pull requests will be peer-reviewed, check [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process) for additional information.
|
||||
|
||||
### Continuous Integration [2.iv]
|
||||
|
||||
@@ -109,7 +109,7 @@ The tests aim to cover both typical usage and corner cases, but are quantified b
|
||||
|
||||
### 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.
|
||||
`rclcpp_action` follows the recommendations for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#code-coverage), and opts to use line coverage instead of branch coverage.
|
||||
|
||||
This includes:
|
||||
|
||||
@@ -119,11 +119,11 @@ This includes:
|
||||
|
||||
Changes are required to make a best effort to keep or increase coverage before being accepted, but decreases are allowed if properly justified and accepted by reviewers.
|
||||
|
||||
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastCompletedBuild/cobertura/src_ros2_rclcpp_rclcpp_action_src/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://index.ros.org/doc/ros2/Contributing/ROS-2-On-boarding-Guide/#note-on-coverage-runs).
|
||||
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastCompletedBuild/cobertura/src_ros2_rclcpp_rclcpp_action_src/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#note-on-coverage-runs).
|
||||
|
||||
### Performance [4.iv]
|
||||
|
||||
`rclcpp_action` follows the recommendations for performance testing of C/C++ code in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#performance), and opts to do performance analysis on each release rather than each change.
|
||||
`rclcpp_action` follows the recommendations for performance testing of C/C++ code in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#performance), and opts to do performance analysis on each release rather than each change.
|
||||
|
||||
The performance tests of `rclcpp_action` are located in the [test/benchmark directory](https://github.com/ros2/rclcpp/tree/master/rclcpp_action/test/benchmark).
|
||||
|
||||
@@ -135,7 +135,7 @@ Changes that introduce regressions in performance must be adequately justified i
|
||||
|
||||
### 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.
|
||||
`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://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#linters-and-static-analysis). Passing implies there are no linter/static errors when testing against CI of supported platforms.
|
||||
|
||||
Currently nightly test results can be seen here:
|
||||
* [linux-aarch64_release](https://ci.ros2.org/view/nightly/job/nightly_linux-aarch64_release/lastBuild/testReport/rclcpp_action/)
|
||||
|
||||
@@ -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>7.0.1</version>
|
||||
<version>8.2.0</version>
|
||||
<description>Adds action APIs for C++.</description>
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
<maintainer email="mabel@openrobotics.org">Mabel Zhang</maintainer>
|
||||
|
||||
@@ -2,6 +2,15 @@
|
||||
Changelog for package rclcpp_components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
8.2.0 (2021-03-31)
|
||||
------------------
|
||||
|
||||
8.1.0 (2021-03-25)
|
||||
------------------
|
||||
|
||||
8.0.0 (2021-03-23)
|
||||
------------------
|
||||
|
||||
7.0.1 (2021-03-22)
|
||||
------------------
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ This document is a declaration of software quality for the `rclcpp_components` p
|
||||
|
||||
The package `rclcpp_components` claims to be in the **Quality Level 1** category.
|
||||
|
||||
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#package-quality-categories) of the ROS2 developer guide.
|
||||
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://www.ros.org/reps/rep-2004.html) 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).
|
||||
`rclcpp_components` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#versioning).
|
||||
|
||||
### Version Stability [1.ii]
|
||||
|
||||
@@ -37,11 +37,11 @@ All installed headers are in the `include` directory of the package, headers in
|
||||
|
||||
## 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).
|
||||
`rclcpp_components` follows the recommended guidelines for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process).
|
||||
|
||||
### 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.
|
||||
All changes will occur through a pull request, check [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process) for additional information.
|
||||
|
||||
### Contributor Origin [2.ii]
|
||||
|
||||
@@ -49,7 +49,7 @@ This package uses DCO as its confirmation of contributor origin policy. More inf
|
||||
|
||||
### Peer Review Policy [2.iii]
|
||||
|
||||
All pull requests will be peer-reviewed, check [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process) for additional information.
|
||||
All pull requests will be peer-reviewed, check [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process) for additional information.
|
||||
|
||||
### Continuous Integration [2.iv]
|
||||
|
||||
@@ -109,7 +109,7 @@ The tests aim to cover both typical usage and corner cases, but are quantified b
|
||||
|
||||
### 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.
|
||||
`rclcpp_components` follows the recommendations for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#code-coverage), and opts to use line coverage instead of branch coverage.
|
||||
|
||||
This includes:
|
||||
|
||||
@@ -119,11 +119,11 @@ This includes:
|
||||
|
||||
Changes are required to make a best effort to keep or increase coverage before being accepted, but decreases are allowed if properly justified and accepted by reviewers.
|
||||
|
||||
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastCompletedBuild/cobertura/src_ros2_rclcpp_rclcpp_components_src/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://index.ros.org/doc/ros2/Contributing/ROS-2-On-boarding-Guide/#note-on-coverage-runs).
|
||||
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastCompletedBuild/cobertura/src_ros2_rclcpp_rclcpp_components_src/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#note-on-coverage-runs).
|
||||
|
||||
### Performance [4.iv]
|
||||
|
||||
`rclcpp_components` follows the recommendations for performance testing of C/C++ code in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#performance), and opts to do performance analysis on each release rather than each change.
|
||||
`rclcpp_components` follows the recommendations for performance testing of C/C++ code in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#performance), and opts to do performance analysis on each release rather than each change.
|
||||
|
||||
The performance tests of `rclcpp_components` are located in the [test/benchmark directory](https://github.com/ros2/rclcpp/tree/master/rclcpp_components/test/benchmark).
|
||||
|
||||
@@ -135,7 +135,7 @@ Changes that introduce regressions in performance must be adequately justified i
|
||||
|
||||
### 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.
|
||||
`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://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#linters-and-static-analysis). Passing implies there are no linter/static errors when testing against CI of supported platforms.
|
||||
|
||||
Currently nightly test results can be seen here:
|
||||
* [linux-aarch64_release](https://ci.ros2.org/view/nightly/job/nightly_linux-aarch64_release/lastBuild/testReport/rclcpp_components/)
|
||||
|
||||
@@ -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>7.0.1</version>
|
||||
<version>8.2.0</version>
|
||||
<description>Package containing tools for dynamically loadable components</description>
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
<maintainer email="mabel@openrobotics.org">Mabel Zhang</maintainer>
|
||||
|
||||
@@ -3,6 +3,22 @@ Changelog for package rclcpp_lifecycle
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
8.2.0 (2021-03-31)
|
||||
------------------
|
||||
* Fix flaky lifecycle node tests (`#1606 <https://github.com/ros2/rclcpp/issues/1606>`_)
|
||||
* Clock subscription callback group spins in its own thread (`#1556 <https://github.com/ros2/rclcpp/issues/1556>`_)
|
||||
* Delete debug messages (`#1602 <https://github.com/ros2/rclcpp/issues/1602>`_)
|
||||
* add automatically_add_executor_with_node option (`#1594 <https://github.com/ros2/rclcpp/issues/1594>`_)
|
||||
* Contributors: BriceRenaudeau, Ivan Santiago Paunovic, Jacob Perron, anaelle-sw
|
||||
|
||||
8.1.0 (2021-03-25)
|
||||
------------------
|
||||
|
||||
8.0.0 (2021-03-23)
|
||||
------------------
|
||||
* make rcl_lifecyle_com_interface optional in lifecycle nodes (`#1507 <https://github.com/ros2/rclcpp/issues/1507>`_)
|
||||
* Contributors: Karsten Knese
|
||||
|
||||
7.0.1 (2021-03-22)
|
||||
------------------
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ This document is a declaration of software quality for the `rclcpp_lifecycle` pa
|
||||
|
||||
The package `rclcpp_lifecycle` claims to be in the **Quality Level 1** category when used with a **Quality Level 1** middleware.
|
||||
|
||||
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#package-quality-categories) of the ROS2 developer guide.
|
||||
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://www.ros.org/reps/rep-2004.html) of the ROS2 developer guide.
|
||||
|
||||
## Version Policy [1]
|
||||
|
||||
### Version Scheme [1.i]
|
||||
|
||||
`rclcpp_lifecycle` 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).
|
||||
`rclcpp_lifecycle` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#versioning).
|
||||
|
||||
### Version Stability [1.ii]
|
||||
|
||||
@@ -37,11 +37,11 @@ All installed headers are in the `include` directory of the package, headers in
|
||||
|
||||
## Change Control Process [2]
|
||||
|
||||
`rclcpp_lifecycle` 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).
|
||||
`rclcpp_lifecycle` follows the recommended guidelines for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process).
|
||||
|
||||
### 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.
|
||||
All changes will occur through a pull request, check [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process) for additional information.
|
||||
|
||||
### Contributor Origin [2.ii]
|
||||
|
||||
@@ -49,7 +49,7 @@ This package uses DCO as its confirmation of contributor origin policy. More inf
|
||||
|
||||
### Peer Review Policy [2.iii]
|
||||
|
||||
All pull requests will be peer-reviewed, check [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process) for additional information.
|
||||
All pull requests will be peer-reviewed, check [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process) for additional information.
|
||||
|
||||
### Continuous Integration [2.iv]
|
||||
|
||||
@@ -109,7 +109,7 @@ The tests aim to cover both typical usage and corner cases, but are quantified b
|
||||
|
||||
### Coverage [4.iii]
|
||||
|
||||
`rclcpp_lifecycle` 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.
|
||||
`rclcpp_lifecycle` follows the recommendations for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#code-coverage), and opts to use line coverage instead of branch coverage.
|
||||
|
||||
This includes:
|
||||
|
||||
@@ -119,11 +119,11 @@ This includes:
|
||||
|
||||
Changes are required to make a best effort to keep or increase coverage before being accepted, but decreases are allowed if properly justified and accepted by reviewers.
|
||||
|
||||
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastCompletedBuild/cobertura/src_ros2_rclcpp_rclcpp_lifecycle_src/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://index.ros.org/doc/ros2/Contributing/ROS-2-On-boarding-Guide/#note-on-coverage-runs).
|
||||
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastCompletedBuild/cobertura/src_ros2_rclcpp_rclcpp_lifecycle_src/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#note-on-coverage-runs).
|
||||
|
||||
### Performance [4.iv]
|
||||
|
||||
`rclcpp_lifecycle` follows the recommendations for performance testing of C/C++ code in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#performance), and opts to do performance analysis on each release rather than each change.
|
||||
`rclcpp_lifecycle` follows the recommendations for performance testing of C/C++ code in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#performance), and opts to do performance analysis on each release rather than each change.
|
||||
|
||||
The performance tests of `rclcpp_lifecycle` are located in the [test/benchmark directory](https://github.com/ros2/rclcpp/tree/master/rclcpp_lifecycle/test/benchmark).
|
||||
|
||||
@@ -135,7 +135,7 @@ Changes that introduce regressions in performance must be adequately justified i
|
||||
|
||||
### Linters and Static Analysis [4.v]
|
||||
|
||||
`rclcpp_lifecycle` 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.
|
||||
`rclcpp_lifecycle` uses and passes all the ROS2 standard linters and static analysis tools for a C++ package as described in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#linters-and-static-analysis). Passing implies there are no linter/static errors when testing against CI of supported platforms.
|
||||
|
||||
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_lifecycle/)
|
||||
|
||||
@@ -127,23 +127,27 @@ public:
|
||||
/**
|
||||
* \param[in] node_name Name of the node.
|
||||
* \param[in] options Additional options to control creation of the node.
|
||||
* \param[in] enable_communication_interface Deciding whether the communication interface of the underlying rcl_lifecycle_node shall be enabled.
|
||||
*/
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
explicit LifecycleNode(
|
||||
const std::string & node_name,
|
||||
const rclcpp::NodeOptions & options = rclcpp::NodeOptions());
|
||||
const rclcpp::NodeOptions & options = rclcpp::NodeOptions(),
|
||||
bool enable_communication_interface = true);
|
||||
|
||||
/// Create a node based on the node name and a rclcpp::Context.
|
||||
/**
|
||||
* \param[in] node_name Name of the node.
|
||||
* \param[in] namespace_ Namespace of the node.
|
||||
* \param[in] options Additional options to control creation of the node.
|
||||
* \param[in] enable_communication_interface Deciding whether the communication interface of the underlying rcl_lifecycle_node shall be enabled.
|
||||
*/
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
LifecycleNode(
|
||||
const std::string & node_name,
|
||||
const std::string & namespace_,
|
||||
const rclcpp::NodeOptions & options = rclcpp::NodeOptions());
|
||||
const rclcpp::NodeOptions & options = rclcpp::NodeOptions(),
|
||||
bool enable_communication_interface = true);
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
virtual ~LifecycleNode();
|
||||
@@ -175,11 +179,16 @@ public:
|
||||
/// Create and return a callback group.
|
||||
/**
|
||||
* \param[in] group_type callback group type to create by this method.
|
||||
* \param[in] automatically_add_to_executor_with_node A boolean that
|
||||
* determines whether a callback group is automatically added to an executor
|
||||
* with the node with which it is associated.
|
||||
* \return a callback group
|
||||
*/
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
rclcpp::CallbackGroup::SharedPtr
|
||||
create_callback_group(rclcpp::CallbackGroupType group_type);
|
||||
create_callback_group(
|
||||
rclcpp::CallbackGroupType group_type,
|
||||
bool automatically_add_to_executor_with_node = true);
|
||||
|
||||
/// Return the list of callback groups in the node.
|
||||
/**
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="2">
|
||||
<name>rclcpp_lifecycle</name>
|
||||
<version>7.0.1</version>
|
||||
<version>8.2.0</version>
|
||||
<description>Package containing a prototype for lifecycle implementation</description>
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
<maintainer email="mabel@openrobotics.org">Mabel Zhang</maintainer>
|
||||
|
||||
@@ -47,17 +47,20 @@ namespace rclcpp_lifecycle
|
||||
|
||||
LifecycleNode::LifecycleNode(
|
||||
const std::string & node_name,
|
||||
const rclcpp::NodeOptions & options)
|
||||
const rclcpp::NodeOptions & options,
|
||||
bool enable_communication_interface)
|
||||
: LifecycleNode(
|
||||
node_name,
|
||||
"",
|
||||
options)
|
||||
options,
|
||||
enable_communication_interface)
|
||||
{}
|
||||
|
||||
LifecycleNode::LifecycleNode(
|
||||
const std::string & node_name,
|
||||
const std::string & namespace_,
|
||||
const rclcpp::NodeOptions & options)
|
||||
const rclcpp::NodeOptions & options,
|
||||
bool enable_communication_interface)
|
||||
: node_base_(new rclcpp::node_interfaces::NodeBase(
|
||||
node_name,
|
||||
namespace_,
|
||||
@@ -99,13 +102,14 @@ LifecycleNode::LifecycleNode(
|
||||
node_logging_,
|
||||
node_clock_,
|
||||
node_parameters_,
|
||||
options.clock_qos()
|
||||
options.clock_qos(),
|
||||
options.use_clock_thread()
|
||||
)),
|
||||
node_waitables_(new rclcpp::node_interfaces::NodeWaitables(node_base_.get())),
|
||||
node_options_(options),
|
||||
impl_(new LifecycleNodeInterfaceImpl(node_base_, node_services_))
|
||||
{
|
||||
impl_->init();
|
||||
impl_->init(enable_communication_interface);
|
||||
|
||||
register_on_configure(
|
||||
std::bind(
|
||||
@@ -161,9 +165,10 @@ LifecycleNode::get_logger() const
|
||||
|
||||
rclcpp::CallbackGroup::SharedPtr
|
||||
LifecycleNode::create_callback_group(
|
||||
rclcpp::CallbackGroupType group_type)
|
||||
rclcpp::CallbackGroupType group_type,
|
||||
bool automatically_add_to_executor_with_node)
|
||||
{
|
||||
return node_base_->create_callback_group(group_type);
|
||||
return node_base_->create_callback_group(group_type, automatically_add_to_executor_with_node);
|
||||
}
|
||||
|
||||
const rclcpp::ParameterValue &
|
||||
|
||||
@@ -64,9 +64,7 @@ public:
|
||||
~LifecycleNodeInterfaceImpl()
|
||||
{
|
||||
rcl_node_t * node_handle = node_base_interface_->get_rcl_node_handle();
|
||||
const rcl_node_options_t * node_options = rcl_node_get_options(node_handle);
|
||||
auto ret = rcl_lifecycle_state_machine_fini(
|
||||
&state_machine_, node_handle, &node_options->allocator);
|
||||
auto ret = rcl_lifecycle_state_machine_fini(&state_machine_, node_handle);
|
||||
if (ret != RCL_RET_OK) {
|
||||
RCUTILS_LOG_FATAL_NAMED(
|
||||
"rclcpp_lifecycle",
|
||||
@@ -75,12 +73,16 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
init()
|
||||
init(bool enable_communication_interface = true)
|
||||
{
|
||||
rcl_node_t * node_handle = node_base_interface_->get_rcl_node_handle();
|
||||
const rcl_node_options_t * node_options =
|
||||
rcl_node_get_options(node_base_interface_->get_rcl_node_handle());
|
||||
state_machine_ = rcl_lifecycle_get_zero_initialized_state_machine();
|
||||
auto state_machine_options = rcl_lifecycle_get_default_state_machine_options();
|
||||
state_machine_options.enable_com_interface = enable_communication_interface;
|
||||
state_machine_options.allocator = node_options->allocator;
|
||||
|
||||
// The call to initialize the state machine takes
|
||||
// currently five different typesupports for all publishers/services
|
||||
// created within the RCL_LIFECYCLE structure.
|
||||
@@ -96,94 +98,95 @@ public:
|
||||
rosidl_typesupport_cpp::get_service_type_support_handle<GetAvailableStatesSrv>(),
|
||||
rosidl_typesupport_cpp::get_service_type_support_handle<GetAvailableTransitionsSrv>(),
|
||||
rosidl_typesupport_cpp::get_service_type_support_handle<GetAvailableTransitionsSrv>(),
|
||||
true,
|
||||
&node_options->allocator);
|
||||
&state_machine_options);
|
||||
if (ret != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
std::string("Couldn't initialize state machine for node ") +
|
||||
node_base_interface_->get_name());
|
||||
}
|
||||
|
||||
{ // change_state
|
||||
auto cb = std::bind(
|
||||
&LifecycleNodeInterfaceImpl::on_change_state, this,
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
rclcpp::AnyServiceCallback<ChangeStateSrv> any_cb;
|
||||
any_cb.set(std::move(cb));
|
||||
if (enable_communication_interface) {
|
||||
{ // change_state
|
||||
auto cb = std::bind(
|
||||
&LifecycleNodeInterfaceImpl::on_change_state, this,
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
rclcpp::AnyServiceCallback<ChangeStateSrv> any_cb;
|
||||
any_cb.set(std::move(cb));
|
||||
|
||||
srv_change_state_ = std::make_shared<rclcpp::Service<ChangeStateSrv>>(
|
||||
node_base_interface_->get_shared_rcl_node_handle(),
|
||||
&state_machine_.com_interface.srv_change_state,
|
||||
any_cb);
|
||||
node_services_interface_->add_service(
|
||||
std::dynamic_pointer_cast<rclcpp::ServiceBase>(srv_change_state_),
|
||||
nullptr);
|
||||
}
|
||||
srv_change_state_ = std::make_shared<rclcpp::Service<ChangeStateSrv>>(
|
||||
node_base_interface_->get_shared_rcl_node_handle(),
|
||||
&state_machine_.com_interface.srv_change_state,
|
||||
any_cb);
|
||||
node_services_interface_->add_service(
|
||||
std::dynamic_pointer_cast<rclcpp::ServiceBase>(srv_change_state_),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
{ // get_state
|
||||
auto cb = std::bind(
|
||||
&LifecycleNodeInterfaceImpl::on_get_state, this,
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
rclcpp::AnyServiceCallback<GetStateSrv> any_cb;
|
||||
any_cb.set(std::move(cb));
|
||||
{ // get_state
|
||||
auto cb = std::bind(
|
||||
&LifecycleNodeInterfaceImpl::on_get_state, this,
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
rclcpp::AnyServiceCallback<GetStateSrv> any_cb;
|
||||
any_cb.set(std::move(cb));
|
||||
|
||||
srv_get_state_ = std::make_shared<rclcpp::Service<GetStateSrv>>(
|
||||
node_base_interface_->get_shared_rcl_node_handle(),
|
||||
&state_machine_.com_interface.srv_get_state,
|
||||
any_cb);
|
||||
node_services_interface_->add_service(
|
||||
std::dynamic_pointer_cast<rclcpp::ServiceBase>(srv_get_state_),
|
||||
nullptr);
|
||||
}
|
||||
srv_get_state_ = std::make_shared<rclcpp::Service<GetStateSrv>>(
|
||||
node_base_interface_->get_shared_rcl_node_handle(),
|
||||
&state_machine_.com_interface.srv_get_state,
|
||||
any_cb);
|
||||
node_services_interface_->add_service(
|
||||
std::dynamic_pointer_cast<rclcpp::ServiceBase>(srv_get_state_),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
{ // get_available_states
|
||||
auto cb = std::bind(
|
||||
&LifecycleNodeInterfaceImpl::on_get_available_states, this,
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
rclcpp::AnyServiceCallback<GetAvailableStatesSrv> any_cb;
|
||||
any_cb.set(std::move(cb));
|
||||
{ // get_available_states
|
||||
auto cb = std::bind(
|
||||
&LifecycleNodeInterfaceImpl::on_get_available_states, this,
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
rclcpp::AnyServiceCallback<GetAvailableStatesSrv> any_cb;
|
||||
any_cb.set(std::move(cb));
|
||||
|
||||
srv_get_available_states_ = std::make_shared<rclcpp::Service<GetAvailableStatesSrv>>(
|
||||
node_base_interface_->get_shared_rcl_node_handle(),
|
||||
&state_machine_.com_interface.srv_get_available_states,
|
||||
any_cb);
|
||||
node_services_interface_->add_service(
|
||||
std::dynamic_pointer_cast<rclcpp::ServiceBase>(srv_get_available_states_),
|
||||
nullptr);
|
||||
}
|
||||
srv_get_available_states_ = std::make_shared<rclcpp::Service<GetAvailableStatesSrv>>(
|
||||
node_base_interface_->get_shared_rcl_node_handle(),
|
||||
&state_machine_.com_interface.srv_get_available_states,
|
||||
any_cb);
|
||||
node_services_interface_->add_service(
|
||||
std::dynamic_pointer_cast<rclcpp::ServiceBase>(srv_get_available_states_),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
{ // get_available_transitions
|
||||
auto cb = std::bind(
|
||||
&LifecycleNodeInterfaceImpl::on_get_available_transitions, this,
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
rclcpp::AnyServiceCallback<GetAvailableTransitionsSrv> any_cb;
|
||||
any_cb.set(std::move(cb));
|
||||
{ // get_available_transitions
|
||||
auto cb = std::bind(
|
||||
&LifecycleNodeInterfaceImpl::on_get_available_transitions, this,
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
rclcpp::AnyServiceCallback<GetAvailableTransitionsSrv> any_cb;
|
||||
any_cb.set(std::move(cb));
|
||||
|
||||
srv_get_available_transitions_ =
|
||||
std::make_shared<rclcpp::Service<GetAvailableTransitionsSrv>>(
|
||||
node_base_interface_->get_shared_rcl_node_handle(),
|
||||
&state_machine_.com_interface.srv_get_available_transitions,
|
||||
any_cb);
|
||||
node_services_interface_->add_service(
|
||||
std::dynamic_pointer_cast<rclcpp::ServiceBase>(srv_get_available_transitions_),
|
||||
nullptr);
|
||||
}
|
||||
srv_get_available_transitions_ =
|
||||
std::make_shared<rclcpp::Service<GetAvailableTransitionsSrv>>(
|
||||
node_base_interface_->get_shared_rcl_node_handle(),
|
||||
&state_machine_.com_interface.srv_get_available_transitions,
|
||||
any_cb);
|
||||
node_services_interface_->add_service(
|
||||
std::dynamic_pointer_cast<rclcpp::ServiceBase>(srv_get_available_transitions_),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
{ // get_transition_graph
|
||||
auto cb = std::bind(
|
||||
&LifecycleNodeInterfaceImpl::on_get_transition_graph, this,
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
rclcpp::AnyServiceCallback<GetAvailableTransitionsSrv> any_cb;
|
||||
any_cb.set(std::move(cb));
|
||||
{ // get_transition_graph
|
||||
auto cb = std::bind(
|
||||
&LifecycleNodeInterfaceImpl::on_get_transition_graph, this,
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
rclcpp::AnyServiceCallback<GetAvailableTransitionsSrv> any_cb;
|
||||
any_cb.set(std::move(cb));
|
||||
|
||||
srv_get_transition_graph_ =
|
||||
std::make_shared<rclcpp::Service<GetAvailableTransitionsSrv>>(
|
||||
node_base_interface_->get_shared_rcl_node_handle(),
|
||||
&state_machine_.com_interface.srv_get_transition_graph,
|
||||
any_cb);
|
||||
node_services_interface_->add_service(
|
||||
std::dynamic_pointer_cast<rclcpp::ServiceBase>(srv_get_transition_graph_),
|
||||
nullptr);
|
||||
srv_get_transition_graph_ =
|
||||
std::make_shared<rclcpp::Service<GetAvailableTransitionsSrv>>(
|
||||
node_base_interface_->get_shared_rcl_node_handle(),
|
||||
&state_machine_.com_interface.srv_get_transition_graph,
|
||||
any_cb);
|
||||
node_services_interface_->add_service(
|
||||
std::dynamic_pointer_cast<rclcpp::ServiceBase>(srv_get_transition_graph_),
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -234,6 +234,48 @@ struct PatchTraits<ID, ReturnT(ArgT0, ArgT1, ArgT2, ArgT3, ArgT4, ArgT5)>
|
||||
mock_type, ReturnT, ArgT0, ArgT1, ArgT2, ArgT3, ArgT4, ArgT5);
|
||||
};
|
||||
|
||||
/// Traits specialization for void(ArgT0, ArgT1, ArgT2, ArgT3, ArgT4, ArgT5)
|
||||
/// free functions.
|
||||
/**
|
||||
* Necessary for Mimick macros to adjust accordingly when the return
|
||||
* type is `void`.
|
||||
*
|
||||
* \tparam ID Numerical identifier of the patch. Ought to be unique.
|
||||
* \tparam ArgTx Argument types.
|
||||
*/
|
||||
template<size_t ID,
|
||||
typename ArgT0, typename ArgT1,
|
||||
typename ArgT2, typename ArgT3,
|
||||
typename ArgT4, typename ArgT5>
|
||||
struct PatchTraits<ID, void(ArgT0, ArgT1, ArgT2, ArgT3, ArgT4, ArgT5)>
|
||||
{
|
||||
mmk_mock_define(
|
||||
mock_type, void, ArgT0, ArgT1, ArgT2, ArgT3, ArgT4, ArgT5);
|
||||
};
|
||||
|
||||
/// Traits specialization for
|
||||
/// ReturnT(ArgT0, ArgT1, ArgT2, ArgT3, ArgT4, ArgT5, ArgT6, ArgT7, ArgT8)
|
||||
/// free functions.
|
||||
/**
|
||||
* Necessary for Mimick macros to adjust accordingly when the return
|
||||
* type is `void`.
|
||||
*
|
||||
* \tparam ID Numerical identifier of the patch. Ought to be unique.
|
||||
* \tparam ArgTx Argument types.
|
||||
*/
|
||||
template<size_t ID, typename ReturnT,
|
||||
typename ArgT0, typename ArgT1,
|
||||
typename ArgT2, typename ArgT3,
|
||||
typename ArgT4, typename ArgT5,
|
||||
typename ArgT6, typename ArgT7,
|
||||
typename ArgT8>
|
||||
struct PatchTraits<ID, ReturnT(
|
||||
ArgT0, ArgT1, ArgT2, ArgT3, ArgT4, ArgT5, ArgT6, ArgT7, ArgT8)>
|
||||
{
|
||||
mmk_mock_define(
|
||||
mock_type, ReturnT, ArgT0, ArgT1, ArgT2, ArgT3, ArgT4, ArgT5, ArgT6, ArgT7, ArgT8);
|
||||
};
|
||||
|
||||
/// Traits specialization for void(ArgT0, ArgT1, ArgT2, ArgT3, ArgT4, ArgT5, ArgT6, ArgT7)
|
||||
/// free functions.
|
||||
/**
|
||||
@@ -256,25 +298,6 @@ struct PatchTraits<ID, ReturnT(
|
||||
mock_type, ReturnT, ArgT0, ArgT1, ArgT2, ArgT3, ArgT4, ArgT5, ArgT6, ArgT7, ArgT8, ArgT9);
|
||||
};
|
||||
|
||||
/// Traits specialization for void(ArgT0, ArgT1, ArgT2, ArgT3, ArgT4, ArgT5)
|
||||
/// free functions.
|
||||
/**
|
||||
* Necessary for Mimick macros to adjust accordingly when the return
|
||||
* type is `void`.
|
||||
*
|
||||
* \tparam ID Numerical identifier of the patch. Ought to be unique.
|
||||
* \tparam ArgTx Argument types.
|
||||
*/
|
||||
template<size_t ID,
|
||||
typename ArgT0, typename ArgT1,
|
||||
typename ArgT2, typename ArgT3,
|
||||
typename ArgT4, typename ArgT5>
|
||||
struct PatchTraits<ID, void(ArgT0, ArgT1, ArgT2, ArgT3, ArgT4, ArgT5)>
|
||||
{
|
||||
mmk_mock_define(
|
||||
mock_type, void, ArgT0, ArgT1, ArgT2, ArgT3, ArgT4, ArgT5);
|
||||
};
|
||||
|
||||
/// Generic trampoline to wrap generalized callables in plain functions.
|
||||
/**
|
||||
* \tparam ID Numerical identifier of this trampoline. Ought to be unique.
|
||||
|
||||
@@ -34,6 +34,88 @@
|
||||
using lifecycle_msgs::msg::State;
|
||||
using lifecycle_msgs::msg::Transition;
|
||||
|
||||
static const std::chrono::nanoseconds DEFAULT_EVENT_TIMEOUT = std::chrono::seconds(3);
|
||||
static const std::chrono::nanoseconds DEFAULT_EVENT_SLEEP_PERIOD = std::chrono::milliseconds(100);
|
||||
|
||||
static
|
||||
bool wait_for_event(
|
||||
std::shared_ptr<rclcpp_lifecycle::LifecycleNode> node,
|
||||
std::function<bool()> predicate,
|
||||
std::chrono::nanoseconds timeout,
|
||||
std::chrono::nanoseconds sleep_period)
|
||||
{
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
std::chrono::microseconds time_slept(0);
|
||||
|
||||
bool predicate_result;
|
||||
while (!(predicate_result = predicate()) &&
|
||||
time_slept < std::chrono::duration_cast<std::chrono::microseconds>(timeout))
|
||||
{
|
||||
rclcpp::Event::SharedPtr graph_event = node->get_graph_event();
|
||||
node->wait_for_graph_change(graph_event, sleep_period);
|
||||
time_slept = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::steady_clock::now() - start);
|
||||
}
|
||||
return predicate_result;
|
||||
}
|
||||
|
||||
static
|
||||
bool wait_for_topic(
|
||||
std::shared_ptr<rclcpp_lifecycle::LifecycleNode> node,
|
||||
const std::string & topic,
|
||||
std::chrono::nanoseconds timeout = DEFAULT_EVENT_TIMEOUT,
|
||||
std::chrono::nanoseconds sleep_period = DEFAULT_EVENT_SLEEP_PERIOD)
|
||||
{
|
||||
return wait_for_event(
|
||||
node,
|
||||
[node, topic]()
|
||||
{
|
||||
auto topic_names_and_types = node->get_topic_names_and_types();
|
||||
return topic_names_and_types.end() != topic_names_and_types.find(topic);
|
||||
},
|
||||
timeout,
|
||||
sleep_period);
|
||||
}
|
||||
|
||||
static
|
||||
bool wait_for_service(
|
||||
std::shared_ptr<rclcpp_lifecycle::LifecycleNode> node,
|
||||
const std::string & service,
|
||||
std::chrono::nanoseconds timeout = DEFAULT_EVENT_TIMEOUT,
|
||||
std::chrono::nanoseconds sleep_period = DEFAULT_EVENT_SLEEP_PERIOD)
|
||||
{
|
||||
return wait_for_event(
|
||||
node,
|
||||
[node, service]()
|
||||
{
|
||||
auto service_names_and_types = node->get_service_names_and_types();
|
||||
return service_names_and_types.end() != service_names_and_types.find(service);
|
||||
},
|
||||
timeout,
|
||||
sleep_period);
|
||||
}
|
||||
|
||||
static
|
||||
bool wait_for_service_by_node(
|
||||
std::shared_ptr<rclcpp_lifecycle::LifecycleNode> node,
|
||||
const std::string & node_name,
|
||||
const std::string & service,
|
||||
std::chrono::nanoseconds timeout = DEFAULT_EVENT_TIMEOUT,
|
||||
std::chrono::nanoseconds sleep_period = DEFAULT_EVENT_SLEEP_PERIOD)
|
||||
{
|
||||
return wait_for_event(
|
||||
node,
|
||||
[node, node_name, service]()
|
||||
{
|
||||
auto service_names_and_types_by_node = node->get_service_names_and_types_by_node(
|
||||
node_name, "");
|
||||
return service_names_and_types_by_node.end() != service_names_and_types_by_node.find(
|
||||
service);
|
||||
},
|
||||
timeout,
|
||||
sleep_period);
|
||||
}
|
||||
|
||||
class TestDefaultStateMachine : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
@@ -152,7 +234,7 @@ TEST_F(TestDefaultStateMachine, empty_initializer) {
|
||||
|
||||
TEST_F(TestDefaultStateMachine, empty_initializer_rcl_errors) {
|
||||
{
|
||||
auto patch = mocking_utils::patch_and_return(
|
||||
auto patch = mocking_utils::inject_on_return(
|
||||
"lib:rclcpp_lifecycle", rcl_lifecycle_state_machine_init, RCL_RET_ERROR);
|
||||
EXPECT_THROW(
|
||||
std::make_shared<EmptyLifecycleNode>("testnode").reset(),
|
||||
@@ -559,10 +641,8 @@ TEST_F(TestDefaultStateMachine, test_graph_topics) {
|
||||
ASSERT_NE(names.end(), std::find(names.begin(), names.end(), std::string("/testnode")));
|
||||
|
||||
// Other topics may exist for an rclcpp::Node, but just checking the lifecycle one exists
|
||||
ASSERT_TRUE(wait_for_topic(test_node, "/testnode/transition_event"));
|
||||
auto topic_names_and_types = test_node->get_topic_names_and_types();
|
||||
ASSERT_NE(
|
||||
topic_names_and_types.end(),
|
||||
topic_names_and_types.find(std::string("/testnode/transition_event")));
|
||||
EXPECT_STREQ(
|
||||
topic_names_and_types["/testnode/transition_event"][0].c_str(),
|
||||
"lifecycle_msgs/msg/TransitionEvent");
|
||||
@@ -580,39 +660,26 @@ TEST_F(TestDefaultStateMachine, test_graph_topics) {
|
||||
TEST_F(TestDefaultStateMachine, test_graph_services) {
|
||||
auto test_node = std::make_shared<EmptyLifecycleNode>("testnode");
|
||||
|
||||
auto service_names_and_types = test_node->get_service_names_and_types();
|
||||
// These are specific to lifecycle nodes, other services are provided by rclcpp::Node
|
||||
ASSERT_NE(
|
||||
service_names_and_types.end(),
|
||||
service_names_and_types.find(std::string("/testnode/change_state")));
|
||||
ASSERT_TRUE(wait_for_service(test_node, "/testnode/change_state"));
|
||||
ASSERT_TRUE(wait_for_service(test_node, "/testnode/get_available_states"));
|
||||
ASSERT_TRUE(wait_for_service(test_node, "/testnode/get_available_transitions"));
|
||||
ASSERT_TRUE(wait_for_service(test_node, "/testnode/get_state"));
|
||||
ASSERT_TRUE(wait_for_service(test_node, "/testnode/get_transition_graph"));
|
||||
|
||||
auto service_names_and_types = test_node->get_service_names_and_types();
|
||||
EXPECT_STREQ(
|
||||
service_names_and_types["/testnode/change_state"][0].c_str(),
|
||||
"lifecycle_msgs/srv/ChangeState");
|
||||
|
||||
ASSERT_NE(
|
||||
service_names_and_types.end(),
|
||||
service_names_and_types.find(std::string("/testnode/get_available_states")));
|
||||
EXPECT_STREQ(
|
||||
service_names_and_types["/testnode/get_available_states"][0].c_str(),
|
||||
"lifecycle_msgs/srv/GetAvailableStates");
|
||||
|
||||
ASSERT_NE(
|
||||
service_names_and_types.end(),
|
||||
service_names_and_types.find(std::string("/testnode/get_available_transitions")));
|
||||
EXPECT_STREQ(
|
||||
service_names_and_types["/testnode/get_available_transitions"][0].c_str(),
|
||||
"lifecycle_msgs/srv/GetAvailableTransitions");
|
||||
|
||||
ASSERT_NE(
|
||||
service_names_and_types.end(),
|
||||
service_names_and_types.find(std::string("/testnode/get_state")));
|
||||
EXPECT_STREQ(
|
||||
service_names_and_types["/testnode/get_state"][0].c_str(),
|
||||
"lifecycle_msgs/srv/GetState");
|
||||
|
||||
ASSERT_NE(
|
||||
service_names_and_types.end(),
|
||||
service_names_and_types.find(std::string("/testnode/get_transition_graph")));
|
||||
EXPECT_STREQ(
|
||||
service_names_and_types["/testnode/get_transition_graph"][0].c_str(),
|
||||
"lifecycle_msgs/srv/GetAvailableTransitions");
|
||||
@@ -621,40 +688,28 @@ TEST_F(TestDefaultStateMachine, test_graph_services) {
|
||||
TEST_F(TestDefaultStateMachine, test_graph_services_by_node) {
|
||||
auto test_node = std::make_shared<EmptyLifecycleNode>("testnode");
|
||||
|
||||
// These are specific to lifecycle nodes, other services are provided by rclcpp::Node
|
||||
ASSERT_TRUE(wait_for_service_by_node(test_node, "testnode", "/testnode/change_state"));
|
||||
ASSERT_TRUE(wait_for_service_by_node(test_node, "testnode", "/testnode/get_available_states"));
|
||||
ASSERT_TRUE(
|
||||
wait_for_service_by_node(test_node, "testnode", "/testnode/get_available_transitions"));
|
||||
ASSERT_TRUE(wait_for_service_by_node(test_node, "testnode", "/testnode/get_state"));
|
||||
ASSERT_TRUE(wait_for_service_by_node(test_node, "testnode", "/testnode/get_transition_graph"));
|
||||
|
||||
auto service_names_and_types_by_node =
|
||||
test_node->get_service_names_and_types_by_node("testnode", "");
|
||||
// These are specific to lifecycle nodes, other services are provided by rclcpp::Node
|
||||
ASSERT_NE(
|
||||
service_names_and_types_by_node.end(),
|
||||
service_names_and_types_by_node.find(std::string("/testnode/change_state")));
|
||||
EXPECT_STREQ(
|
||||
service_names_and_types_by_node["/testnode/change_state"][0].c_str(),
|
||||
"lifecycle_msgs/srv/ChangeState");
|
||||
|
||||
ASSERT_NE(
|
||||
service_names_and_types_by_node.end(),
|
||||
service_names_and_types_by_node.find(std::string("/testnode/get_available_states")));
|
||||
EXPECT_STREQ(
|
||||
service_names_and_types_by_node["/testnode/get_available_states"][0].c_str(),
|
||||
"lifecycle_msgs/srv/GetAvailableStates");
|
||||
|
||||
ASSERT_NE(
|
||||
service_names_and_types_by_node.end(),
|
||||
service_names_and_types_by_node.find(std::string("/testnode/get_available_transitions")));
|
||||
EXPECT_STREQ(
|
||||
service_names_and_types_by_node["/testnode/get_available_transitions"][0].c_str(),
|
||||
"lifecycle_msgs/srv/GetAvailableTransitions");
|
||||
|
||||
ASSERT_NE(
|
||||
service_names_and_types_by_node.end(),
|
||||
service_names_and_types_by_node.find(std::string("/testnode/get_state")));
|
||||
EXPECT_STREQ(
|
||||
service_names_and_types_by_node["/testnode/get_state"][0].c_str(),
|
||||
"lifecycle_msgs/srv/GetState");
|
||||
|
||||
ASSERT_NE(
|
||||
service_names_and_types_by_node.end(),
|
||||
service_names_and_types_by_node.find(std::string("/testnode/get_transition_graph")));
|
||||
EXPECT_STREQ(
|
||||
service_names_and_types_by_node["/testnode/get_transition_graph"][0].c_str(),
|
||||
"lifecycle_msgs/srv/GetAvailableTransitions");
|
||||
@@ -666,7 +721,7 @@ TEST_F(TestDefaultStateMachine, test_callback_groups) {
|
||||
EXPECT_EQ(groups.size(), 1u);
|
||||
|
||||
auto group = test_node->create_callback_group(
|
||||
rclcpp::CallbackGroupType::MutuallyExclusive);
|
||||
rclcpp::CallbackGroupType::MutuallyExclusive, true);
|
||||
EXPECT_NE(nullptr, group);
|
||||
|
||||
groups = test_node->get_callback_groups();
|
||||
|
||||
Reference in New Issue
Block a user