Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7e3504fcf | ||
|
|
474720511e | ||
|
|
51a4b2155e | ||
|
|
aa3a65d3ff | ||
|
|
f986ca3edc | ||
|
|
2562f715ab | ||
|
|
3ab6571593 | ||
|
|
bc8c71b63f | ||
|
|
63e79223f9 | ||
|
|
92ece94ca3 | ||
|
|
a7ec7d9243 | ||
|
|
06a4a56017 | ||
|
|
98a62f6a18 | ||
|
|
dbb4c354d6 | ||
|
|
0088e35052 | ||
|
|
3fa511a8a0 |
@@ -2,6 +2,23 @@
|
||||
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>`_)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 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>8.0.0</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>
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,24 @@ 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_;
|
||||
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 +281,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;
|
||||
|
||||
@@ -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,12 @@ Changelog for package rclcpp_action
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
8.2.0 (2021-03-31)
|
||||
------------------
|
||||
|
||||
8.1.0 (2021-03-25)
|
||||
------------------
|
||||
|
||||
8.0.0 (2021-03-23)
|
||||
------------------
|
||||
|
||||
|
||||
@@ -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>8.0.0</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,12 @@
|
||||
Changelog for package rclcpp_components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
8.2.0 (2021-03-31)
|
||||
------------------
|
||||
|
||||
8.1.0 (2021-03-25)
|
||||
------------------
|
||||
|
||||
8.0.0 (2021-03-23)
|
||||
------------------
|
||||
|
||||
|
||||
@@ -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>8.0.0</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,17 @@ 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>`_)
|
||||
|
||||
@@ -179,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>8.0.0</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>
|
||||
|
||||
@@ -102,7 +102,8 @@ 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),
|
||||
@@ -164,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 &
|
||||
|
||||
@@ -63,11 +63,8 @@ public:
|
||||
|
||||
~LifecycleNodeInterfaceImpl()
|
||||
{
|
||||
fprintf(stderr, "oh yeah destructuro\n");
|
||||
rcl_node_t * node_handle = node_base_interface_->get_rcl_node_handle();
|
||||
fprintf(stderr, "oh yeah end destructuro\n");
|
||||
auto ret = rcl_lifecycle_state_machine_fini(&state_machine_, node_handle);
|
||||
fprintf(stderr, "oh yeah end destructuro222\n");
|
||||
if (ret != RCL_RET_OK) {
|
||||
RCUTILS_LOG_FATAL_NAMED(
|
||||
"rclcpp_lifecycle",
|
||||
@@ -103,7 +100,6 @@ public:
|
||||
rosidl_typesupport_cpp::get_service_type_support_handle<GetAvailableTransitionsSrv>(),
|
||||
&state_machine_options);
|
||||
if (ret != RCL_RET_OK) {
|
||||
fprintf(stderr, "oh yeah %s\n", node_base_interface_->get_name());
|
||||
throw std::runtime_error(
|
||||
std::string("Couldn't initialize state machine for node ") +
|
||||
node_base_interface_->get_name());
|
||||
|
||||
@@ -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:
|
||||
@@ -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