Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f331f90a9 | ||
|
|
620fcf1e05 | ||
|
|
d407a5e331 | ||
|
|
7f411371b3 | ||
|
|
76e2b2677b | ||
|
|
5049c45f85 | ||
|
|
4691063a61 | ||
|
|
f294488e17 | ||
|
|
8a02e3934c | ||
|
|
fff009a751 | ||
|
|
2204e44305 | ||
|
|
fcbe64cff4 | ||
|
|
c366e531fa | ||
|
|
5ffc963e1a | ||
|
|
7f7ffcf6ed |
@@ -2,6 +2,22 @@
|
||||
Changelog for package rclcpp
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
24.0.0 (2023-11-06)
|
||||
-------------------
|
||||
* fix (signal_handler.hpp): spelling (`#2356 <https://github.com/ros2/rclcpp/issues/2356>`_)
|
||||
* Updates to not use std::move in some places. (`#2353 <https://github.com/ros2/rclcpp/issues/2353>`_)
|
||||
* rclcpp::Time::max() clock type support. (`#2352 <https://github.com/ros2/rclcpp/issues/2352>`_)
|
||||
* Serialized Messages with Topic Statistics (`#2274 <https://github.com/ros2/rclcpp/issues/2274>`_)
|
||||
* Add a custom deleter when constructing rcl_service_t (`#2351 <https://github.com/ros2/rclcpp/issues/2351>`_)
|
||||
* Disable the loaned messages inside the executor. (`#2335 <https://github.com/ros2/rclcpp/issues/2335>`_)
|
||||
* Use message_info in SubscriptionTopicStatistics instead of typed message (`#2337 <https://github.com/ros2/rclcpp/issues/2337>`_)
|
||||
* Add missing 'enable_rosout' comments (`#2345 <https://github.com/ros2/rclcpp/issues/2345>`_)
|
||||
* Adjust rclcpp usage of type description service (`#2344 <https://github.com/ros2/rclcpp/issues/2344>`_)
|
||||
* address rate related flaky tests. (`#2329 <https://github.com/ros2/rclcpp/issues/2329>`_)
|
||||
* Fixes pointed out by the clang analyzer. (`#2339 <https://github.com/ros2/rclcpp/issues/2339>`_)
|
||||
* Remove useless ROSRate class (`#2326 <https://github.com/ros2/rclcpp/issues/2326>`_)
|
||||
* Contributors: Alexey Merzlyakov, Chris Lalancette, Jiaqi Li, Lucas Wendland, Michael Carroll, Michael Orlov, Tomoya Fujita, Zard-C
|
||||
|
||||
23.2.0 (2023-10-09)
|
||||
-------------------
|
||||
* add clients & services count (`#2072 <https://github.com/ros2/rclcpp/issues/2072>`_)
|
||||
|
||||
@@ -50,8 +50,8 @@ template<
|
||||
typename SubscriptionT,
|
||||
typename MessageMemoryStrategyT,
|
||||
typename NodeParametersT,
|
||||
typename NodeTopicsT,
|
||||
typename ROSMessageType = typename SubscriptionT::ROSMessageType>
|
||||
typename NodeTopicsT
|
||||
>
|
||||
typename std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
NodeParametersT & node_parameters,
|
||||
@@ -70,7 +70,7 @@ create_subscription(
|
||||
using rclcpp::node_interfaces::get_node_topics_interface;
|
||||
auto node_topics_interface = get_node_topics_interface(node_topics);
|
||||
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>>
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics>
|
||||
subscription_topic_stats = nullptr;
|
||||
|
||||
if (rclcpp::detail::resolve_enable_topic_statistics(
|
||||
@@ -80,8 +80,7 @@ create_subscription(
|
||||
if (options.topic_stats_options.publish_period <= std::chrono::milliseconds(0)) {
|
||||
throw std::invalid_argument(
|
||||
"topic_stats_options.publish_period must be greater than 0, specified value of " +
|
||||
std::to_string(options.topic_stats_options.publish_period.count()) +
|
||||
" ms");
|
||||
std::to_string(options.topic_stats_options.publish_period.count()) + " ms");
|
||||
}
|
||||
|
||||
std::shared_ptr<Publisher<statistics_msgs::msg::MetricsMessage>>
|
||||
@@ -91,12 +90,12 @@ create_subscription(
|
||||
options.topic_stats_options.publish_topic,
|
||||
qos);
|
||||
|
||||
subscription_topic_stats = std::make_shared<
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>
|
||||
>(node_topics_interface->get_node_base_interface()->get_name(), publisher);
|
||||
subscription_topic_stats =
|
||||
std::make_shared<rclcpp::topic_statistics::SubscriptionTopicStatistics>(
|
||||
node_topics_interface->get_node_base_interface()->get_name(), publisher);
|
||||
|
||||
std::weak_ptr<
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics
|
||||
> weak_subscription_topic_stats(subscription_topic_stats);
|
||||
auto sub_call_back = [weak_subscription_topic_stats]() {
|
||||
auto subscription_topic_stats = weak_subscription_topic_stats.lock();
|
||||
|
||||
@@ -467,7 +467,7 @@ private:
|
||||
auto ptr = MessageAllocTraits::allocate(allocator, 1);
|
||||
MessageAllocTraits::construct(allocator, ptr, *message);
|
||||
|
||||
subscription->provide_intra_process_data(std::move(MessageUniquePtr(ptr, deleter)));
|
||||
subscription->provide_intra_process_data(MessageUniquePtr(ptr, deleter));
|
||||
}
|
||||
|
||||
continue;
|
||||
@@ -510,7 +510,7 @@ private:
|
||||
MessageAllocTraits::construct(allocator, ptr, *message);
|
||||
|
||||
ros_message_subscription->provide_intra_process_message(
|
||||
std::move(MessageUniquePtr(ptr, deleter)));
|
||||
MessageUniquePtr(ptr, deleter));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,9 +126,6 @@ private:
|
||||
std::shared_ptr<std::pair<std::string, std::string>> logger_sublogger_pairname_ = nullptr;
|
||||
|
||||
public:
|
||||
RCLCPP_PUBLIC
|
||||
Logger(const Logger &) = default;
|
||||
|
||||
/// Get the name of this logger.
|
||||
/**
|
||||
* \return the full name of the logger including any prefixes, or
|
||||
|
||||
@@ -43,6 +43,7 @@ public:
|
||||
* - arguments = {}
|
||||
* - parameter_overrides = {}
|
||||
* - use_global_arguments = true
|
||||
* - enable_rosout = true
|
||||
* - use_intra_process_comms = false
|
||||
* - enable_topic_statistics = false
|
||||
* - start_parameter_services = true
|
||||
|
||||
@@ -390,7 +390,7 @@ public:
|
||||
if (this->can_loan_messages()) {
|
||||
// we release the ownership from the rclpp::LoanedMessage instance
|
||||
// and let the middleware clean up the memory.
|
||||
this->do_loaned_message_publish(std::move(loaned_msg.release()));
|
||||
this->do_loaned_message_publish(loaned_msg.release());
|
||||
} else {
|
||||
// we don't release the ownership, let the middleware copy the ros message
|
||||
// and thus the destructor of rclcpp::LoanedMessage cleans up the memory.
|
||||
|
||||
@@ -184,16 +184,6 @@ public:
|
||||
explicit WallRate(const Duration & period);
|
||||
};
|
||||
|
||||
class ROSRate : public Rate
|
||||
{
|
||||
public:
|
||||
RCLCPP_PUBLIC
|
||||
explicit ROSRate(const double rate);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
explicit ROSRate(const Duration & period);
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__RATE_HPP_
|
||||
|
||||
@@ -104,7 +104,7 @@ public:
|
||||
|
||||
private:
|
||||
using SubscriptionTopicStatisticsSharedPtr =
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>>;
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics>;
|
||||
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Subscription)
|
||||
@@ -316,7 +316,7 @@ public:
|
||||
if (subscription_topic_statistics_) {
|
||||
const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
|
||||
const auto time = rclcpp::Time(nanos.time_since_epoch().count());
|
||||
subscription_topic_statistics_->handle_message(*typed_message, time);
|
||||
subscription_topic_statistics_->handle_message(message_info.get_rmw_message_info(), time);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,8 +325,20 @@ public:
|
||||
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
|
||||
const rclcpp::MessageInfo & message_info) override
|
||||
{
|
||||
// TODO(wjwwood): enable topic statistics for serialized messages
|
||||
std::chrono::time_point<std::chrono::system_clock> now;
|
||||
if (subscription_topic_statistics_) {
|
||||
// get current time before executing callback to
|
||||
// exclude callback duration from topic statistics result.
|
||||
now = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
any_callback_.dispatch(serialized_message, message_info);
|
||||
|
||||
if (subscription_topic_statistics_) {
|
||||
const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
|
||||
const auto time = rclcpp::Time(nanos.time_since_epoch().count());
|
||||
subscription_topic_statistics_->handle_message(message_info.get_rmw_message_info(), time);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -357,7 +369,7 @@ public:
|
||||
if (subscription_topic_statistics_) {
|
||||
const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
|
||||
const auto time = rclcpp::Time(nanos.time_since_epoch().count());
|
||||
subscription_topic_statistics_->handle_message(*typed_message, time);
|
||||
subscription_topic_statistics_->handle_message(message_info.get_rmw_message_info(), time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,15 +75,14 @@ template<
|
||||
typename CallbackT,
|
||||
typename AllocatorT,
|
||||
typename SubscriptionT = rclcpp::Subscription<MessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType,
|
||||
typename ROSMessageType = typename SubscriptionT::ROSMessageType
|
||||
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType
|
||||
>
|
||||
SubscriptionFactory
|
||||
create_subscription_factory(
|
||||
CallbackT && callback,
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
|
||||
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat,
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>>
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics>
|
||||
subscription_topic_stats = nullptr
|
||||
)
|
||||
{
|
||||
|
||||
@@ -189,7 +189,7 @@ public:
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
static Time
|
||||
max();
|
||||
max(rcl_clock_type_t clock_type = RCL_SYSTEM_TIME); // NOLINT
|
||||
|
||||
/// Get the seconds since epoch
|
||||
/**
|
||||
|
||||
@@ -48,21 +48,12 @@ using libstatistics_collector::moving_average_statistics::StatisticData;
|
||||
/**
|
||||
* Class used to collect, measure, and publish topic statistics data. Current statistics
|
||||
* supported for subscribers are received message age and received message period.
|
||||
*
|
||||
* \tparam CallbackMessageT the subscribed message type
|
||||
*/
|
||||
template<typename CallbackMessageT>
|
||||
*/
|
||||
class SubscriptionTopicStatistics
|
||||
{
|
||||
using TopicStatsCollector =
|
||||
libstatistics_collector::topic_statistics_collector::TopicStatisticsCollector<
|
||||
CallbackMessageT>;
|
||||
using ReceivedMessageAge =
|
||||
libstatistics_collector::topic_statistics_collector::ReceivedMessageAgeCollector<
|
||||
CallbackMessageT>;
|
||||
using ReceivedMessagePeriod =
|
||||
libstatistics_collector::topic_statistics_collector::ReceivedMessagePeriodCollector<
|
||||
CallbackMessageT>;
|
||||
using TopicStatsCollector = libstatistics_collector::TopicStatisticsCollector;
|
||||
using ReceivedMessageAge = libstatistics_collector::ReceivedMessageAgeCollector;
|
||||
using ReceivedMessagePeriod = libstatistics_collector::ReceivedMessagePeriodCollector;
|
||||
|
||||
public:
|
||||
/// Construct a SubscriptionTopicStatistics object.
|
||||
@@ -101,16 +92,16 @@ public:
|
||||
/**
|
||||
* This method acquires a lock to prevent race conditions to collectors list.
|
||||
*
|
||||
* \param received_message the message received by the subscription
|
||||
* \param message_info the message info corresponding to the received message
|
||||
* \param now_nanoseconds current time in nanoseconds
|
||||
*/
|
||||
virtual void handle_message(
|
||||
const CallbackMessageT & received_message,
|
||||
const rmw_message_info_t & message_info,
|
||||
const rclcpp::Time now_nanoseconds) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
for (const auto & collector : subscriber_statistics_collectors_) {
|
||||
collector->OnMessageReceived(received_message, now_nanoseconds.nanoseconds());
|
||||
collector->OnMessageReceived(message_info, now_nanoseconds.nanoseconds());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>23.2.0</version>
|
||||
<version>24.0.0</version>
|
||||
<description>The ROS client library in C++.</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -462,7 +462,7 @@ template<Context::ShutdownType shutdown_type>
|
||||
std::vector<rclcpp::Context::ShutdownCallback>
|
||||
Context::get_shutdown_callback() const
|
||||
{
|
||||
const auto get_callback_vector = [this](auto & mutex, auto & callback_set) {
|
||||
const auto get_callback_vector = [](auto & mutex, auto & callback_set) {
|
||||
const std::lock_guard<std::mutex> lock(mutex);
|
||||
std::vector<rclcpp::Context::ShutdownCallback> callbacks;
|
||||
for (auto & callback : callback_set) {
|
||||
@@ -496,7 +496,7 @@ Context::sleep_for(const std::chrono::nanoseconds & nanoseconds)
|
||||
std::unique_lock<std::mutex> lock(interrupt_mutex_);
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
// this will release the lock while waiting
|
||||
interrupt_condition_variable_.wait_for(lock, nanoseconds);
|
||||
interrupt_condition_variable_.wait_for(lock, time_left);
|
||||
time_left -= std::chrono::steady_clock::now() - start;
|
||||
}
|
||||
} while (time_left > std::chrono::nanoseconds::zero() && this->is_valid());
|
||||
|
||||
@@ -669,6 +669,11 @@ Executor::execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
|
||||
subscription->get_topic_name(),
|
||||
[&]() {return subscription->take_type_erased(message.get(), message_info);},
|
||||
[&]() {subscription->handle_message(message, message_info);});
|
||||
// TODO(clalancette): In the case that the user is using the MessageMemoryPool,
|
||||
// and they take a shared_ptr reference to the message in the callback, this can
|
||||
// inadvertently return the message to the pool when the user is still using it.
|
||||
// This is a bug that needs to be fixed in the pool, and we should probably have
|
||||
// a custom deleter for the message that actually does the return_message().
|
||||
subscription->return_message(message);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -84,23 +84,31 @@ public:
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
auto rcl_node = node_base->get_rcl_node_handle();
|
||||
rcl_ret_t rcl_ret = rcl_node_type_description_service_init(rcl_node);
|
||||
auto * rcl_node = node_base->get_rcl_node_handle();
|
||||
std::shared_ptr<rcl_service_t> rcl_srv(
|
||||
new rcl_service_t,
|
||||
[rcl_node, logger = this->logger_](rcl_service_t * service)
|
||||
{
|
||||
if (rcl_service_fini(service, rcl_node) != RCL_RET_OK) {
|
||||
RCLCPP_ERROR(
|
||||
logger,
|
||||
"Error in destruction of rcl service handle [~/get_type_description]: %s",
|
||||
rcl_get_error_string().str);
|
||||
rcl_reset_error();
|
||||
}
|
||||
delete service;
|
||||
});
|
||||
*rcl_srv = rcl_get_zero_initialized_service();
|
||||
rcl_ret_t rcl_ret = rcl_node_type_description_service_init(rcl_srv.get(), rcl_node);
|
||||
|
||||
if (rcl_ret != RCL_RET_OK) {
|
||||
RCLCPP_ERROR(
|
||||
logger_, "Failed to initialize ~/get_type_description_service: %s",
|
||||
logger_, "Failed to initialize ~/get_type_description service: %s",
|
||||
rcl_get_error_string().str);
|
||||
throw std::runtime_error(
|
||||
"Failed to initialize ~/get_type_description service.");
|
||||
}
|
||||
|
||||
rcl_service_t * rcl_srv = nullptr;
|
||||
rcl_ret = rcl_node_get_type_description_service(rcl_node, &rcl_srv);
|
||||
if (rcl_ret != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
"Failed to get initialized ~/get_type_description service from rcl.");
|
||||
}
|
||||
|
||||
rclcpp::AnyServiceCallback<ServiceT> cb;
|
||||
cb.set(
|
||||
[this](
|
||||
@@ -124,18 +132,6 @@ public:
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
~NodeTypeDescriptionsImpl()
|
||||
{
|
||||
if (
|
||||
type_description_srv_ &&
|
||||
RCL_RET_OK != rcl_node_type_description_service_fini(node_base_->get_rcl_node_handle()))
|
||||
{
|
||||
RCLCPP_ERROR(
|
||||
logger_,
|
||||
"Error in shutdown of get_type_description service: %s", rcl_get_error_string().str);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
NodeTypeDescriptions::NodeTypeDescriptions(
|
||||
|
||||
@@ -67,7 +67,8 @@ Rate::sleep()
|
||||
// Calculate the time to sleep
|
||||
auto time_to_sleep = next_interval - now;
|
||||
// Sleep (will get interrupted by ctrl-c, may not sleep full time)
|
||||
return clock_->sleep_for(time_to_sleep);
|
||||
clock_->sleep_for(time_to_sleep);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -102,12 +103,4 @@ WallRate::WallRate(const Duration & period)
|
||||
: Rate(period, std::make_shared<Clock>(RCL_STEADY_TIME))
|
||||
{}
|
||||
|
||||
ROSRate::ROSRate(const double rate)
|
||||
: Rate(rate, std::make_shared<Clock>(RCL_ROS_TIME))
|
||||
{}
|
||||
|
||||
ROSRate::ROSRate(const Duration & period)
|
||||
: Rate(period, std::make_shared<Clock>(RCL_ROS_TIME))
|
||||
{}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
bool
|
||||
install(SignalHandlerOptions signal_handler_options = SignalHandlerOptions::All);
|
||||
|
||||
/// Uninstall the signal handler for SIGINT/SIGTERM and join the dedicated singal handling
|
||||
/// Uninstall the signal handler for SIGINT/SIGTERM and join the dedicated signal handling
|
||||
/// thread.
|
||||
/**
|
||||
* Also restores the previous signal handler.
|
||||
@@ -189,7 +189,7 @@ private:
|
||||
|
||||
// Whether or not a signal has been received.
|
||||
std::atomic_bool signal_received_ = false;
|
||||
// A thread to which singal handling tasks are deferred.
|
||||
// A thread to which signal handling tasks are deferred.
|
||||
std::thread signal_handler_thread_;
|
||||
|
||||
// A mutex used to synchronize the install() and uninstall() methods.
|
||||
|
||||
@@ -298,7 +298,20 @@ SubscriptionBase::setup_intra_process(
|
||||
bool
|
||||
SubscriptionBase::can_loan_messages() const
|
||||
{
|
||||
return rcl_subscription_can_loan_messages(subscription_handle_.get());
|
||||
bool retval = rcl_subscription_can_loan_messages(subscription_handle_.get());
|
||||
if (retval) {
|
||||
// TODO(clalancette): The loaned message interface is currently not safe to use with
|
||||
// shared_ptr callbacks. If a user takes a copy of the shared_ptr, it can get freed from
|
||||
// underneath them via rcl_return_loaned_message_from_subscription(). The correct solution is
|
||||
// to return the loaned message in a custom deleter, but that needs to be carefully handled
|
||||
// with locking. Warn the user about this until we fix it.
|
||||
RCLCPP_WARN_ONCE(
|
||||
this->node_logger_,
|
||||
"Loaned messages are only safe with const ref subscription callbacks. "
|
||||
"If you are using any other kind of subscriptions, "
|
||||
"set the ROS_DISABLE_LOANED_MESSAGES environment variable to 1 (the default).");
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
rclcpp::Waitable::SharedPtr
|
||||
|
||||
@@ -276,9 +276,9 @@ Time::operator-=(const rclcpp::Duration & rhs)
|
||||
}
|
||||
|
||||
Time
|
||||
Time::max()
|
||||
Time::max(rcl_clock_type_t clock_type)
|
||||
{
|
||||
return Time(std::numeric_limits<int32_t>::max(), 999999999);
|
||||
return Time(std::numeric_limits<int32_t>::max(), 999999999, clock_type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -644,6 +644,7 @@ TYPED_TEST(TestExecutors, testRaceConditionAddNode)
|
||||
break;
|
||||
}
|
||||
total += k * (i + 42);
|
||||
(void)total;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -43,10 +43,9 @@ TEST_F(TestNodeTypeDescriptions, disabled_no_service)
|
||||
node_options.append_parameter_override("start_type_description_service", false);
|
||||
rclcpp::Node node{"node", "ns", node_options};
|
||||
|
||||
rcl_node_t * rcl_node = node.get_node_base_interface()->get_rcl_node_handle();
|
||||
rcl_service_t * srv = nullptr;
|
||||
rcl_ret_t ret = rcl_node_get_type_description_service(rcl_node, &srv);
|
||||
ASSERT_EQ(RCL_RET_NOT_INIT, ret);
|
||||
auto services = node.get_node_graph_interface()->get_service_names_and_types_by_node(
|
||||
"node", "/ns");
|
||||
EXPECT_TRUE(services.find("/ns/node/get_type_description") == services.end());
|
||||
}
|
||||
|
||||
TEST_F(TestNodeTypeDescriptions, enabled_creates_service)
|
||||
@@ -55,9 +54,8 @@ TEST_F(TestNodeTypeDescriptions, enabled_creates_service)
|
||||
node_options.append_parameter_override("start_type_description_service", true);
|
||||
rclcpp::Node node{"node", "ns", node_options};
|
||||
|
||||
rcl_node_t * rcl_node = node.get_node_base_interface()->get_rcl_node_handle();
|
||||
rcl_service_t * srv = nullptr;
|
||||
rcl_ret_t ret = rcl_node_get_type_description_service(rcl_node, &srv);
|
||||
ASSERT_EQ(RCL_RET_OK, ret);
|
||||
ASSERT_NE(nullptr, srv);
|
||||
auto services = node.get_node_graph_interface()->get_service_names_and_types_by_node(
|
||||
"node", "/ns");
|
||||
|
||||
EXPECT_TRUE(services.find("/ns/node/get_type_description") != services.end());
|
||||
}
|
||||
|
||||
@@ -289,7 +289,7 @@ public:
|
||||
}
|
||||
|
||||
bool
|
||||
use_take_shared_method() const
|
||||
use_take_shared_method() const override
|
||||
{
|
||||
return take_shared_method;
|
||||
}
|
||||
|
||||
@@ -482,7 +482,7 @@ public:
|
||||
|
||||
void publish_loaned_message(rclcpp::LoanedMessage<MessageT, AllocatorT> && loaned_msg)
|
||||
{
|
||||
this->do_loaned_message_publish(std::move(loaned_msg.release()));
|
||||
this->do_loaned_message_publish(loaned_msg.release());
|
||||
}
|
||||
|
||||
void call_default_incompatible_qos_callback(rclcpp::QOSOfferedIncompatibleQoSInfo & event) const
|
||||
|
||||
@@ -21,12 +21,24 @@
|
||||
|
||||
#include "../utils/rclcpp_gtest_macros.hpp"
|
||||
|
||||
/*
|
||||
Basic tests for the Rate, WallRate and ROSRate classes.
|
||||
*/
|
||||
TEST(TestRate, rate_basics) {
|
||||
rclcpp::init(0, nullptr);
|
||||
class TestRate : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
void SetUp()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
{
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Basic tests for the Rate and WallRate classes.
|
||||
*/
|
||||
TEST_F(TestRate, rate_basics) {
|
||||
auto period = std::chrono::milliseconds(1000);
|
||||
auto offset = std::chrono::milliseconds(500);
|
||||
auto epsilon = std::chrono::milliseconds(100);
|
||||
@@ -79,13 +91,9 @@ TEST(TestRate, rate_basics) {
|
||||
auto five = std::chrono::system_clock::now();
|
||||
delta = five - four;
|
||||
ASSERT_TRUE(epsilon > delta);
|
||||
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
TEST(TestRate, wall_rate_basics) {
|
||||
rclcpp::init(0, nullptr);
|
||||
|
||||
TEST_F(TestRate, wall_rate_basics) {
|
||||
auto period = std::chrono::milliseconds(100);
|
||||
auto offset = std::chrono::milliseconds(50);
|
||||
auto epsilon = std::chrono::milliseconds(1);
|
||||
@@ -140,77 +148,12 @@ TEST(TestRate, wall_rate_basics) {
|
||||
auto five = std::chrono::steady_clock::now();
|
||||
delta = five - four;
|
||||
EXPECT_GT(epsilon, delta);
|
||||
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
TEST(TestRate, ros_rate_basics) {
|
||||
rclcpp::init(0, nullptr);
|
||||
|
||||
auto period = std::chrono::milliseconds(100);
|
||||
auto offset = std::chrono::milliseconds(50);
|
||||
auto epsilon = std::chrono::milliseconds(1);
|
||||
double overrun_ratio = 1.5;
|
||||
|
||||
rclcpp::Clock clock(RCL_ROS_TIME);
|
||||
|
||||
auto start = clock.now();
|
||||
rclcpp::ROSRate r(period);
|
||||
EXPECT_EQ(rclcpp::Duration(period), r.period());
|
||||
// suppress deprecated warnings
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
ASSERT_FALSE(r.is_steady());
|
||||
// suppress deprecated warnings
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
ASSERT_EQ(RCL_ROS_TIME, r.get_type());
|
||||
ASSERT_TRUE(r.sleep());
|
||||
auto one = clock.now();
|
||||
auto delta = one - start;
|
||||
EXPECT_LT(rclcpp::Duration(period), delta);
|
||||
EXPECT_GT(rclcpp::Duration(period * overrun_ratio), delta);
|
||||
|
||||
clock.sleep_for(offset);
|
||||
ASSERT_TRUE(r.sleep());
|
||||
auto two = clock.now();
|
||||
delta = two - start;
|
||||
EXPECT_LT(rclcpp::Duration(2 * period), delta + epsilon);
|
||||
EXPECT_GT(rclcpp::Duration(2 * period * overrun_ratio), delta);
|
||||
|
||||
clock.sleep_for(offset);
|
||||
auto two_offset = clock.now();
|
||||
r.reset();
|
||||
ASSERT_TRUE(r.sleep());
|
||||
auto three = clock.now();
|
||||
delta = three - two_offset;
|
||||
EXPECT_LT(rclcpp::Duration(period), delta);
|
||||
EXPECT_GT(rclcpp::Duration(period * overrun_ratio), delta);
|
||||
|
||||
clock.sleep_for(offset + period);
|
||||
auto four = clock.now();
|
||||
ASSERT_FALSE(r.sleep());
|
||||
auto five = clock.now();
|
||||
delta = five - four;
|
||||
EXPECT_GT(rclcpp::Duration(epsilon), delta);
|
||||
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
/*
|
||||
Basic test for the deprecated GenericRate class.
|
||||
*/
|
||||
TEST(TestRate, generic_rate) {
|
||||
TEST_F(TestRate, generic_rate) {
|
||||
auto period = std::chrono::milliseconds(100);
|
||||
auto offset = std::chrono::milliseconds(50);
|
||||
auto epsilon = std::chrono::milliseconds(1);
|
||||
@@ -325,13 +268,13 @@ TEST(TestRate, generic_rate) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestRate, from_double) {
|
||||
TEST_F(TestRate, from_double) {
|
||||
{
|
||||
rclcpp::Rate rate(1.0);
|
||||
EXPECT_EQ(rclcpp::Duration(std::chrono::seconds(1)), rate.period());
|
||||
}
|
||||
{
|
||||
rclcpp::WallRate rate(2.0);
|
||||
rclcpp::Rate rate(2.0);
|
||||
EXPECT_EQ(rclcpp::Duration(std::chrono::milliseconds(500)), rate.period());
|
||||
}
|
||||
{
|
||||
@@ -339,12 +282,12 @@ TEST(TestRate, from_double) {
|
||||
EXPECT_EQ(rclcpp::Duration(std::chrono::seconds(2)), rate.period());
|
||||
}
|
||||
{
|
||||
rclcpp::ROSRate rate(4.0);
|
||||
rclcpp::WallRate rate(4.0);
|
||||
EXPECT_EQ(rclcpp::Duration(std::chrono::milliseconds(250)), rate.period());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestRate, clock_types) {
|
||||
TEST_F(TestRate, clock_types) {
|
||||
{
|
||||
rclcpp::Rate rate(1.0, std::make_shared<rclcpp::Clock>(RCL_SYSTEM_TIME));
|
||||
// suppress deprecated warnings
|
||||
@@ -404,7 +347,7 @@ TEST(TestRate, clock_types) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestRate, incorrect_constuctor) {
|
||||
TEST_F(TestRate, incorrect_constuctor) {
|
||||
// Constructor with 0-frequency
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
rclcpp::Rate rate(0.0),
|
||||
|
||||
@@ -363,10 +363,27 @@ TEST_F(TestTime, seconds) {
|
||||
}
|
||||
|
||||
TEST_F(TestTime, test_max) {
|
||||
const rclcpp::Time time_max = rclcpp::Time::max();
|
||||
const rclcpp::Time max_time(std::numeric_limits<int32_t>::max(), 999999999);
|
||||
EXPECT_DOUBLE_EQ(max_time.seconds(), time_max.seconds());
|
||||
EXPECT_EQ(max_time.nanoseconds(), time_max.nanoseconds());
|
||||
// Same clock types
|
||||
for (rcl_clock_type_t type = RCL_ROS_TIME;
|
||||
type != RCL_STEADY_TIME; type = static_cast<rcl_clock_type_t>(type + 1))
|
||||
{
|
||||
const rclcpp::Time time_max = rclcpp::Time::max(type);
|
||||
const rclcpp::Time max_time(std::numeric_limits<int32_t>::max(), 999999999, type);
|
||||
EXPECT_DOUBLE_EQ(max_time.seconds(), time_max.seconds());
|
||||
EXPECT_EQ(max_time.nanoseconds(), time_max.nanoseconds());
|
||||
}
|
||||
// Different clock types
|
||||
{
|
||||
const rclcpp::Time time_max = rclcpp::Time::max(RCL_ROS_TIME);
|
||||
const rclcpp::Time max_time(std::numeric_limits<int32_t>::max(), 999999999, RCL_STEADY_TIME);
|
||||
EXPECT_ANY_THROW((void)(time_max == max_time));
|
||||
EXPECT_ANY_THROW((void)(time_max != max_time));
|
||||
EXPECT_ANY_THROW((void)(time_max <= max_time));
|
||||
EXPECT_ANY_THROW((void)(time_max >= max_time));
|
||||
EXPECT_ANY_THROW((void)(time_max < max_time));
|
||||
EXPECT_ANY_THROW((void)(time_max > max_time));
|
||||
EXPECT_ANY_THROW((void)(time_max - max_time));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestTime, test_constructor_from_rcl_time_point) {
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
@@ -22,12 +21,12 @@
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "libstatistics_collector/moving_average_statistics/types.hpp"
|
||||
|
||||
#include "rclcpp/create_publisher.hpp"
|
||||
#include "rclcpp/msg/message_with_header.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
@@ -36,10 +35,10 @@
|
||||
#include "rclcpp/topic_statistics/subscription_topic_statistics.hpp"
|
||||
|
||||
#include "statistics_msgs/msg/metrics_message.hpp"
|
||||
#include "statistics_msgs/msg/statistic_data_point.hpp"
|
||||
#include "statistics_msgs/msg/statistic_data_type.hpp"
|
||||
|
||||
#include "test_msgs/msg/empty.hpp"
|
||||
#include "test_msgs/msg/strings.hpp"
|
||||
|
||||
#include "test_topic_stats_utils.hpp"
|
||||
|
||||
@@ -67,7 +66,6 @@ constexpr const std::chrono::seconds kUnstableMessageAgeWindowDuration{
|
||||
constexpr const std::chrono::seconds kUnstableMessageAgeOffset{std::chrono::seconds{1}};
|
||||
} // namespace
|
||||
|
||||
using rclcpp::msg::MessageWithHeader;
|
||||
using test_msgs::msg::Empty;
|
||||
using rclcpp::topic_statistics::SubscriptionTopicStatistics;
|
||||
using statistics_msgs::msg::MetricsMessage;
|
||||
@@ -76,114 +74,73 @@ using statistics_msgs::msg::StatisticDataType;
|
||||
using libstatistics_collector::moving_average_statistics::StatisticData;
|
||||
|
||||
/**
|
||||
* Wrapper class to test and expose parts of the SubscriptionTopicStatistics<T> class.
|
||||
* \tparam CallbackMessageT
|
||||
* Wrapper class to test and expose parts of the SubscriptionTopicStatistics class.
|
||||
*/
|
||||
template<typename CallbackMessageT>
|
||||
class TestSubscriptionTopicStatistics : public SubscriptionTopicStatistics<CallbackMessageT>
|
||||
class TestSubscriptionTopicStatistics : public SubscriptionTopicStatistics
|
||||
{
|
||||
public:
|
||||
TestSubscriptionTopicStatistics(
|
||||
const std::string & node_name,
|
||||
rclcpp::Publisher<statistics_msgs::msg::MetricsMessage>::SharedPtr publisher)
|
||||
: SubscriptionTopicStatistics<CallbackMessageT>(node_name, publisher)
|
||||
: SubscriptionTopicStatistics(node_name, std::move(publisher))
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~TestSubscriptionTopicStatistics() = default;
|
||||
~TestSubscriptionTopicStatistics() override = default;
|
||||
|
||||
/// Exposed for testing
|
||||
std::vector<StatisticData> get_current_collector_data() const
|
||||
{
|
||||
return SubscriptionTopicStatistics<CallbackMessageT>::get_current_collector_data();
|
||||
}
|
||||
using SubscriptionTopicStatistics::get_current_collector_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Empty publisher node: used to publish empty messages
|
||||
* PublisherNode wrapper: used to create publisher node
|
||||
*/
|
||||
class EmptyPublisher : public rclcpp::Node
|
||||
template<typename MessageT>
|
||||
class PublisherNode : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
EmptyPublisher(
|
||||
PublisherNode(
|
||||
const std::string & name, const std::string & topic,
|
||||
const std::chrono::milliseconds & publish_period = std::chrono::milliseconds{100})
|
||||
: Node(name)
|
||||
{
|
||||
publisher_ = create_publisher<Empty>(topic, 10);
|
||||
publisher_ = create_publisher<MessageT>(topic, 10);
|
||||
publish_timer_ = this->create_wall_timer(
|
||||
publish_period, [this]() {
|
||||
this->publish_message();
|
||||
});
|
||||
}
|
||||
|
||||
virtual ~EmptyPublisher() = default;
|
||||
~PublisherNode() override = default;
|
||||
|
||||
private:
|
||||
void publish_message()
|
||||
{
|
||||
auto msg = Empty{};
|
||||
auto msg = MessageT{};
|
||||
publisher_->publish(msg);
|
||||
}
|
||||
|
||||
rclcpp::Publisher<Empty>::SharedPtr publisher_;
|
||||
typename rclcpp::Publisher<MessageT>::SharedPtr publisher_;
|
||||
rclcpp::TimerBase::SharedPtr publish_timer_;
|
||||
};
|
||||
|
||||
/**
|
||||
* MessageWithHeader publisher node: used to publish MessageWithHeader with `header` value set
|
||||
*/
|
||||
class MessageWithHeaderPublisher : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
MessageWithHeaderPublisher(
|
||||
const std::string & name, const std::string & topic,
|
||||
const std::chrono::milliseconds & publish_period = std::chrono::milliseconds{100})
|
||||
: Node(name)
|
||||
{
|
||||
publisher_ = create_publisher<MessageWithHeader>(topic, 10);
|
||||
publish_timer_ = this->create_wall_timer(
|
||||
publish_period, [this]() {
|
||||
this->publish_message();
|
||||
});
|
||||
uniform_dist_ = std::uniform_int_distribution<uint32_t>{1000000, 100000000};
|
||||
}
|
||||
|
||||
virtual ~MessageWithHeaderPublisher() = default;
|
||||
|
||||
private:
|
||||
void publish_message()
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 gen{rd()};
|
||||
uint32_t d = uniform_dist_(gen);
|
||||
auto msg = MessageWithHeader{};
|
||||
// Subtract ~1 second (add some noise for a non-zero standard deviation)
|
||||
// so the received message age calculation is always > 0
|
||||
msg.header.stamp = this->now() - rclcpp::Duration{1, d};
|
||||
publisher_->publish(msg);
|
||||
}
|
||||
|
||||
rclcpp::Publisher<MessageWithHeader>::SharedPtr publisher_;
|
||||
rclcpp::TimerBase::SharedPtr publish_timer_;
|
||||
std::uniform_int_distribution<uint32_t> uniform_dist_;
|
||||
};
|
||||
|
||||
/**
|
||||
* TransitionMessageStamp publisher node : used to publish MessageWithHeader with `header` value set
|
||||
* TransitionMessageStamp publisher emulator node : used to emulate publishing messages by
|
||||
* directly calling rclcpp::Subscription::handle_message(msg_shared_ptr, message_info).
|
||||
* The message age results change during the test.
|
||||
*/
|
||||
|
||||
class TransitionMessageStampPublisher : public rclcpp::Node
|
||||
template<typename MessageT>
|
||||
class TransitionMessageStampPublisherEmulator : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
TransitionMessageStampPublisher(
|
||||
const std::string & name, const std::string & topic,
|
||||
TransitionMessageStampPublisherEmulator(
|
||||
const std::string & name,
|
||||
const std::chrono::seconds transition_duration, const std::chrono::seconds message_age_offset,
|
||||
typename rclcpp::Subscription<MessageT>::SharedPtr subscription,
|
||||
const std::chrono::milliseconds & publish_period = std::chrono::milliseconds{100})
|
||||
: Node(name), transition_duration_(transition_duration), message_age_offset_(message_age_offset)
|
||||
: Node(name), transition_duration_(transition_duration), message_age_offset_(message_age_offset),
|
||||
subscription_(std::move(subscription))
|
||||
{
|
||||
publisher_ = create_publisher<MessageWithHeader>(topic, 10);
|
||||
publish_timer_ = this->create_wall_timer(publish_period, [this]() {this->publish_message();});
|
||||
start_time_ = this->now();
|
||||
}
|
||||
@@ -191,84 +148,66 @@ public:
|
||||
private:
|
||||
void publish_message()
|
||||
{
|
||||
auto msg = MessageWithHeader{};
|
||||
std::shared_ptr<void> msg_shared_ptr = std::make_shared<MessageT>();
|
||||
rmw_message_info_t rmw_message_info = rmw_get_zero_initialized_message_info();
|
||||
|
||||
auto now = this->now();
|
||||
auto elapsed_time = now - start_time_;
|
||||
if (elapsed_time < transition_duration_) {
|
||||
// Apply only to the topic statistics in the first half
|
||||
// Subtract offset so message_age is always >= offset.
|
||||
msg.header.stamp = now - message_age_offset_;
|
||||
rmw_message_info.source_timestamp = (now - message_age_offset_).nanoseconds();
|
||||
} else {
|
||||
msg.header.stamp = now;
|
||||
rmw_message_info.source_timestamp = now.nanoseconds();
|
||||
}
|
||||
publisher_->publish(msg);
|
||||
rclcpp::MessageInfo message_info{rmw_message_info};
|
||||
subscription_->handle_message(msg_shared_ptr, message_info);
|
||||
}
|
||||
|
||||
std::chrono::seconds transition_duration_;
|
||||
std::chrono::seconds message_age_offset_;
|
||||
typename rclcpp::Subscription<MessageT>::SharedPtr subscription_;
|
||||
rclcpp::Time start_time_;
|
||||
|
||||
rclcpp::Publisher<MessageWithHeader>::SharedPtr publisher_;
|
||||
rclcpp::TimerBase::SharedPtr publish_timer_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Empty subscriber node: used to create subscriber topic statistics requirements
|
||||
* Message subscriber node: used to create subscriber with enabled topic statistics collectors
|
||||
*
|
||||
*/
|
||||
class EmptySubscriber : public rclcpp::Node
|
||||
template<typename MessageT>
|
||||
class SubscriberWithTopicStatistics : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
EmptySubscriber(const std::string & name, const std::string & topic)
|
||||
SubscriberWithTopicStatistics(
|
||||
const std::string & name, const std::string & topic,
|
||||
std::chrono::milliseconds publish_period = defaultStatisticsPublishPeriod)
|
||||
: Node(name)
|
||||
{
|
||||
// manually enable topic statistics via options
|
||||
// Manually enable topic statistics via options
|
||||
auto options = rclcpp::SubscriptionOptions();
|
||||
options.topic_stats_options.state = rclcpp::TopicStatisticsState::Enable;
|
||||
options.topic_stats_options.publish_period = publish_period;
|
||||
|
||||
auto callback = [](Empty::UniquePtr msg) {
|
||||
auto callback = [](typename MessageT::UniquePtr msg) {
|
||||
(void) msg;
|
||||
};
|
||||
subscription_ = create_subscription<Empty,
|
||||
std::function<void(Empty::UniquePtr)>>(
|
||||
subscription_ = create_subscription<MessageT,
|
||||
std::function<void(typename MessageT::UniquePtr)>>(
|
||||
topic,
|
||||
rclcpp::QoS(rclcpp::KeepAll()),
|
||||
callback,
|
||||
options);
|
||||
}
|
||||
virtual ~EmptySubscriber() = default;
|
||||
~SubscriberWithTopicStatistics() override = default;
|
||||
|
||||
private:
|
||||
rclcpp::Subscription<Empty>::SharedPtr subscription_;
|
||||
};
|
||||
|
||||
/**
|
||||
* MessageWithHeader subscriber node: used to create subscriber topic statistics requirements
|
||||
*/
|
||||
class MessageWithHeaderSubscriber : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
MessageWithHeaderSubscriber(const std::string & name, const std::string & topic)
|
||||
: Node(name)
|
||||
typename rclcpp::Subscription<MessageT>::SharedPtr get_subscription()
|
||||
{
|
||||
// manually enable topic statistics via options
|
||||
auto options = rclcpp::SubscriptionOptions();
|
||||
options.topic_stats_options.state = rclcpp::TopicStatisticsState::Enable;
|
||||
options.topic_stats_options.publish_period = defaultStatisticsPublishPeriod;
|
||||
|
||||
auto callback = [](MessageWithHeader::UniquePtr msg) {
|
||||
(void) msg;
|
||||
};
|
||||
subscription_ = create_subscription<MessageWithHeader,
|
||||
std::function<void(MessageWithHeader::UniquePtr)>>(
|
||||
topic,
|
||||
rclcpp::QoS(rclcpp::KeepAll()),
|
||||
callback,
|
||||
options);
|
||||
return subscription_;
|
||||
}
|
||||
virtual ~MessageWithHeaderSubscriber() = default;
|
||||
|
||||
private:
|
||||
rclcpp::Subscription<MessageWithHeader>::SharedPtr subscription_;
|
||||
typename rclcpp::Subscription<MessageT>::SharedPtr subscription_;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -277,43 +216,17 @@ private:
|
||||
class TestSubscriptionTopicStatisticsFixture : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp()
|
||||
void SetUp() override
|
||||
{
|
||||
rclcpp::init(0 /* argc */, nullptr /* argv */);
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
void TearDown() override
|
||||
{
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if a received statistics message is empty (no data was observed)
|
||||
* \param message_to_check
|
||||
*/
|
||||
void check_if_statistics_message_is_empty(const MetricsMessage & message_to_check)
|
||||
{
|
||||
for (const auto & stats_point : message_to_check.statistics) {
|
||||
const auto type = stats_point.data_type;
|
||||
switch (type) {
|
||||
case StatisticDataType::STATISTICS_DATA_TYPE_SAMPLE_COUNT:
|
||||
EXPECT_EQ(0, stats_point.data) << "unexpected sample count" << stats_point.data;
|
||||
break;
|
||||
case StatisticDataType::STATISTICS_DATA_TYPE_AVERAGE:
|
||||
case StatisticDataType::STATISTICS_DATA_TYPE_MINIMUM:
|
||||
case StatisticDataType::STATISTICS_DATA_TYPE_MAXIMUM:
|
||||
case StatisticDataType::STATISTICS_DATA_TYPE_STDDEV:
|
||||
EXPECT_TRUE(std::isnan(stats_point.data)) << "unexpected value" << stats_point.data <<
|
||||
" for type:" << type;
|
||||
break;
|
||||
default:
|
||||
FAIL() << "received unknown statistics type: " << std::dec <<
|
||||
static_cast<unsigned int>(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a received statistics message observed data and contains some calculation
|
||||
* \param message_to_check
|
||||
@@ -348,28 +261,13 @@ void check_if_statistic_message_is_populated(const MetricsMessage & message_to_c
|
||||
/**
|
||||
* Test an invalid argument is thrown for a bad input publish period.
|
||||
*/
|
||||
TEST(TestSubscriptionTopicStatistics, test_invalid_publish_period)
|
||||
TEST_F(TestSubscriptionTopicStatisticsFixture, test_invalid_publish_period)
|
||||
{
|
||||
rclcpp::init(0 /* argc */, nullptr /* argv */);
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("test_period_node");
|
||||
|
||||
auto options = rclcpp::SubscriptionOptions();
|
||||
options.topic_stats_options.state = rclcpp::TopicStatisticsState::Enable;
|
||||
options.topic_stats_options.publish_period = std::chrono::milliseconds(0);
|
||||
|
||||
auto callback = [](Empty::UniquePtr msg) {
|
||||
(void) msg;
|
||||
};
|
||||
|
||||
ASSERT_THROW(
|
||||
(node->create_subscription<Empty, std::function<void(Empty::UniquePtr)>>(
|
||||
"should_throw_invalid_arg",
|
||||
rclcpp::QoS(rclcpp::KeepAll()),
|
||||
callback,
|
||||
options)), std::invalid_argument);
|
||||
|
||||
rclcpp::shutdown();
|
||||
SubscriberWithTopicStatistics<Empty>(
|
||||
"test_period_node", "should_throw_invalid_arg", std::chrono::milliseconds(0)
|
||||
),
|
||||
std::invalid_argument);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -378,7 +276,7 @@ TEST(TestSubscriptionTopicStatistics, test_invalid_publish_period)
|
||||
*/
|
||||
TEST_F(TestSubscriptionTopicStatisticsFixture, test_manual_construction)
|
||||
{
|
||||
auto empty_subscriber = std::make_shared<EmptySubscriber>(
|
||||
auto empty_subscriber = std::make_shared<SubscriberWithTopicStatistics<Empty>>(
|
||||
kTestSubNodeName,
|
||||
kTestSubStatsEmptyTopic);
|
||||
|
||||
@@ -389,7 +287,7 @@ TEST_F(TestSubscriptionTopicStatisticsFixture, test_manual_construction)
|
||||
10);
|
||||
|
||||
// Construct a separate instance
|
||||
auto sub_topic_stats = std::make_unique<TestSubscriptionTopicStatistics<Empty>>(
|
||||
auto sub_topic_stats = std::make_unique<TestSubscriptionTopicStatistics>(
|
||||
empty_subscriber->get_name(),
|
||||
topic_stats_publisher);
|
||||
|
||||
@@ -410,7 +308,7 @@ TEST_F(TestSubscriptionTopicStatisticsFixture, test_manual_construction)
|
||||
TEST_F(TestSubscriptionTopicStatisticsFixture, test_receive_stats_for_message_no_header)
|
||||
{
|
||||
// Create an empty publisher
|
||||
auto empty_publisher = std::make_shared<EmptyPublisher>(
|
||||
auto empty_publisher = std::make_shared<PublisherNode<Empty>>(
|
||||
kTestPubNodeName,
|
||||
kTestSubStatsEmptyTopic);
|
||||
// empty_subscriber has a topic statistics instance as part of its subscription
|
||||
@@ -422,7 +320,7 @@ TEST_F(TestSubscriptionTopicStatisticsFixture, test_receive_stats_for_message_no
|
||||
"/statistics",
|
||||
kNumExpectedMessages);
|
||||
|
||||
auto empty_subscriber = std::make_shared<EmptySubscriber>(
|
||||
auto empty_subscriber = std::make_shared<SubscriberWithTopicStatistics<Empty>>(
|
||||
kTestSubNodeName,
|
||||
kTestSubStatsEmptyTopic);
|
||||
|
||||
@@ -432,74 +330,7 @@ TEST_F(TestSubscriptionTopicStatisticsFixture, test_receive_stats_for_message_no
|
||||
ex.add_node(empty_subscriber);
|
||||
|
||||
// Spin and get future
|
||||
ex.spin_until_future_complete(
|
||||
statistics_listener->GetFuture(),
|
||||
kTestTimeout);
|
||||
|
||||
// Compare message counts, sample count should be the same as published and received count
|
||||
EXPECT_EQ(kNumExpectedMessages, statistics_listener->GetNumberOfMessagesReceived());
|
||||
|
||||
// Check the received message total count
|
||||
const auto received_messages = statistics_listener->GetReceivedMessages();
|
||||
EXPECT_EQ(kNumExpectedMessages, received_messages.size());
|
||||
|
||||
// check the type of statistics that were received and their counts
|
||||
uint64_t message_age_count{0};
|
||||
uint64_t message_period_count{0};
|
||||
|
||||
std::set<std::string> received_metrics;
|
||||
for (const auto & msg : received_messages) {
|
||||
if (msg.metrics_source == "message_age") {
|
||||
message_age_count++;
|
||||
}
|
||||
if (msg.metrics_source == "message_period") {
|
||||
message_period_count++;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(kNumExpectedMessageAgeMessages, message_age_count);
|
||||
EXPECT_EQ(kNumExpectedMessagePeriodMessages, message_period_count);
|
||||
|
||||
// Check the collected statistics for message period.
|
||||
// Message age statistics will not be calculated because Empty messages
|
||||
// don't have a `header` with timestamp. This means that we expect to receive a `message_age`
|
||||
// and `message_period` message for each empty message published.
|
||||
for (const auto & msg : received_messages) {
|
||||
if (msg.metrics_source == kMessageAgeSourceLabel) {
|
||||
check_if_statistics_message_is_empty(msg);
|
||||
} else if (msg.metrics_source == kMessagePeriodSourceLabel) {
|
||||
check_if_statistic_message_is_populated(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestSubscriptionTopicStatisticsFixture, test_receive_stats_for_message_with_header)
|
||||
{
|
||||
// Create a MessageWithHeader publisher
|
||||
auto msg_with_header_publisher = std::make_shared<MessageWithHeaderPublisher>(
|
||||
kTestPubNodeName,
|
||||
kTestSubStatsTopic);
|
||||
// empty_subscriber has a topic statistics instance as part of its subscription
|
||||
// this will listen to and generate statistics for the empty message
|
||||
|
||||
// Create a listener for topic statistics messages
|
||||
auto statistics_listener = std::make_shared<rclcpp::topic_statistics::MetricsMessageSubscriber>(
|
||||
"test_receive_stats_for_message_with_header",
|
||||
"/statistics",
|
||||
kNumExpectedMessages);
|
||||
|
||||
auto msg_with_header_subscriber = std::make_shared<MessageWithHeaderSubscriber>(
|
||||
kTestSubNodeName,
|
||||
kTestSubStatsTopic);
|
||||
|
||||
rclcpp::executors::SingleThreadedExecutor ex;
|
||||
ex.add_node(msg_with_header_publisher);
|
||||
ex.add_node(statistics_listener);
|
||||
ex.add_node(msg_with_header_subscriber);
|
||||
|
||||
// Spin and get future
|
||||
ex.spin_until_future_complete(
|
||||
statistics_listener->GetFuture(),
|
||||
kTestTimeout);
|
||||
ex.spin_until_future_complete(statistics_listener->GetFuture(), kTestTimeout);
|
||||
|
||||
// Compare message counts, sample count should be the same as published and received count
|
||||
EXPECT_EQ(kNumExpectedMessages, statistics_listener->GetNumberOfMessagesReceived());
|
||||
@@ -524,6 +355,7 @@ TEST_F(TestSubscriptionTopicStatisticsFixture, test_receive_stats_for_message_wi
|
||||
EXPECT_EQ(kNumExpectedMessageAgeMessages, message_age_count);
|
||||
EXPECT_EQ(kNumExpectedMessagePeriodMessages, message_period_count);
|
||||
|
||||
// Check the collected statistics for message period.
|
||||
for (const auto & msg : received_messages) {
|
||||
check_if_statistic_message_is_populated(msg);
|
||||
}
|
||||
@@ -531,23 +363,27 @@ TEST_F(TestSubscriptionTopicStatisticsFixture, test_receive_stats_for_message_wi
|
||||
|
||||
TEST_F(TestSubscriptionTopicStatisticsFixture, test_receive_stats_include_window_reset)
|
||||
{
|
||||
// Create a MessageWithHeader publisher
|
||||
auto msg_with_header_publisher = std::make_shared<TransitionMessageStampPublisher>(
|
||||
kTestPubNodeName, kTestSubStatsTopic, kUnstableMessageAgeWindowDuration,
|
||||
kUnstableMessageAgeOffset);
|
||||
|
||||
// msg_with_header_subscriber has a topic statistics instance as part of its
|
||||
// msg_subscriber_with_topic_statistics has a topic statistics instance as part of its
|
||||
// subscription this will listen to and generate statistics
|
||||
auto msg_with_header_subscriber =
|
||||
std::make_shared<MessageWithHeaderSubscriber>(kTestSubNodeName, kTestSubStatsTopic);
|
||||
auto msg_subscriber_with_topic_statistics =
|
||||
std::make_shared<SubscriberWithTopicStatistics<test_msgs::msg::Strings>>(
|
||||
kTestSubNodeName,
|
||||
kTestSubStatsTopic);
|
||||
|
||||
// Create a message publisher
|
||||
auto msg_publisher =
|
||||
std::make_shared<TransitionMessageStampPublisherEmulator<test_msgs::msg::Strings>>(
|
||||
kTestPubNodeName, kUnstableMessageAgeWindowDuration,
|
||||
kUnstableMessageAgeOffset, msg_subscriber_with_topic_statistics->get_subscription());
|
||||
|
||||
// Create a listener for topic statistics messages
|
||||
auto statistics_listener = std::make_shared<rclcpp::topic_statistics::MetricsMessageSubscriber>(
|
||||
"test_receive_stats_include_window_reset", "/statistics", kNumExpectedMessages);
|
||||
|
||||
rclcpp::executors::SingleThreadedExecutor ex;
|
||||
ex.add_node(msg_with_header_publisher);
|
||||
ex.add_node(msg_publisher);
|
||||
ex.add_node(statistics_listener);
|
||||
ex.add_node(msg_with_header_subscriber);
|
||||
ex.add_node(msg_subscriber_with_topic_statistics);
|
||||
|
||||
// Spin and get future
|
||||
ex.spin_until_future_complete(statistics_listener->GetFuture(), kTestTimeout);
|
||||
|
||||
@@ -3,6 +3,9 @@ Changelog for package rclcpp_action
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
24.0.0 (2023-11-06)
|
||||
-------------------
|
||||
|
||||
23.2.0 (2023-10-09)
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -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>23.2.0</version>
|
||||
<version>24.0.0</version>
|
||||
<description>Adds action APIs for C++.</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
Changelog for package rclcpp_components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
24.0.0 (2023-11-06)
|
||||
-------------------
|
||||
|
||||
23.2.0 (2023-10-09)
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -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>23.2.0</version>
|
||||
<version>24.0.0</version>
|
||||
<description>Package containing tools for dynamically loadable components</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -3,6 +3,11 @@ Changelog for package rclcpp_lifecycle
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
24.0.0 (2023-11-06)
|
||||
-------------------
|
||||
* Fix rclcpp_lifecycle inclusion on Windows. (`#2331 <https://github.com/ros2/rclcpp/issues/2331>`_)
|
||||
* Contributors: Chris Lalancette
|
||||
|
||||
23.2.0 (2023-10-09)
|
||||
-------------------
|
||||
* add clients & services count (`#2072 <https://github.com/ros2/rclcpp/issues/2072>`_)
|
||||
|
||||
@@ -21,6 +21,14 @@
|
||||
#include "rclcpp_lifecycle/visibility_control.h"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
|
||||
// When windows.h is included, ERROR is defined as a macro. So the use of it later in this file,
|
||||
// even as an enum, causes compilation errors. Work around this by undefining the macro here,
|
||||
// and then redefining when this header is finished being included.
|
||||
#if defined(_WIN32)
|
||||
#pragma push_macro("ERROR")
|
||||
#undef ERROR
|
||||
#endif
|
||||
|
||||
namespace rclcpp_lifecycle
|
||||
{
|
||||
namespace node_interfaces
|
||||
@@ -108,6 +116,10 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp_lifecycle
|
||||
|
||||
#if defined(_WIN32)
|
||||
#pragma pop_macro("ERROR")
|
||||
#endif
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(
|
||||
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface, lifecycle_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>23.2.0</version>
|
||||
<version>24.0.0</version>
|
||||
<description>Package containing a prototype for lifecycle implementation</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
Reference in New Issue
Block a user