Compare commits
15 Commits
master
...
ch3/type_d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0dddb16bed | ||
|
|
a0a2a067d8 | ||
|
|
094618a044 | ||
|
|
f5e08c2d0c | ||
|
|
016cfeac99 | ||
|
|
a13e16e2cb | ||
|
|
aad8cb53ad | ||
|
|
8c0161a07f | ||
|
|
a7f05a904a | ||
|
|
d7245365ed | ||
|
|
3310f9eaed | ||
|
|
785a70d604 | ||
|
|
9984197c29 | ||
|
|
e9b1004247 | ||
|
|
e64627004f |
13
.github/workflows/mirror-rolling-to-master.yaml
vendored
13
.github/workflows/mirror-rolling-to-master.yaml
vendored
@@ -1,13 +0,0 @@
|
||||
name: Mirror rolling to master
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ rolling ]
|
||||
|
||||
jobs:
|
||||
mirror-to-master:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: zofrex/mirror-branch@v1
|
||||
with:
|
||||
target-branch: master
|
||||
@@ -1,2 +0,0 @@
|
||||
# This file was generated by https://github.com/audrow/update-ros2-repos
|
||||
* @ivanpauno @hidmic @wjwwood
|
||||
@@ -2,6 +2,19 @@
|
||||
Changelog for package rclcpp
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
29.3.0 (2024-12-20)
|
||||
-------------------
|
||||
* Fix transient local IPC publish (`#2708 <https://github.com/ros2/rclcpp/issues/2708>`_)
|
||||
* apply actual QoS from rmw to the IPC publisher. (`#2707 <https://github.com/ros2/rclcpp/issues/2707>`_)
|
||||
* Adding in topic name to logging on IPC issues (`#2706 <https://github.com/ros2/rclcpp/issues/2706>`_)
|
||||
* fix TestTimeSource.ROS_time_valid_attach_detach. (`#2700 <https://github.com/ros2/rclcpp/issues/2700>`_)
|
||||
* Update docstring for `rclcpp::Node::now()` (`#2696 <https://github.com/ros2/rclcpp/issues/2696>`_)
|
||||
* Re-enable executor test on rmw_connextdds. (`#2693 <https://github.com/ros2/rclcpp/issues/2693>`_)
|
||||
* Fix warnings on Windows. (`#2692 <https://github.com/ros2/rclcpp/issues/2692>`_)
|
||||
* Omnibus fixes for running tests with Connext. (`#2684 <https://github.com/ros2/rclcpp/issues/2684>`_)
|
||||
* fix(Executor): Fix segfault if callback group is deleted during rmw_wait (`#2683 <https://github.com/ros2/rclcpp/issues/2683>`_)
|
||||
* Contributors: Chris Lalancette, Jeffery Hsu, Patrick Roncagliolo, Steve Macenski, Tomoya Fujita, jmachowinski
|
||||
|
||||
29.2.0 (2024-11-25)
|
||||
-------------------
|
||||
* accept custom allocator for LoanedMessage. (`#2672 <https://github.com/ros2/rclcpp/issues/2672>`_)
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
// Copyright 2025 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__TYPE_DESCRIPTION_CONVERSIONS_HPP_
|
||||
#define RCLCPP__DYNAMIC_TYPESUPPORT__TYPE_DESCRIPTION_CONVERSIONS_HPP_
|
||||
|
||||
#include "rosidl_runtime_cpp/type_description/individual_type_description__struct.hpp"
|
||||
#include "rosidl_runtime_cpp/type_description/type_description__struct.hpp"
|
||||
#include "rosidl_runtime_cpp/type_description/type_source__struct.hpp"
|
||||
#include "type_description_interfaces/msg/individual_type_description.hpp"
|
||||
#include "type_description_interfaces/msg/type_description.hpp"
|
||||
#include "type_description_interfaces/msg/type_source.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace dynamic_typesupport
|
||||
{
|
||||
|
||||
// IndividualTypeDescription =======================================================================
|
||||
|
||||
/// Convert a runtime individual type description struct to its corresponding message.
|
||||
/**
|
||||
* This function converts a rosidl_runtime_cpp::type_description::IndividualTypeDescription
|
||||
* struct to the corresponding type_description_interfaces/msg/IndividualTypeDescription
|
||||
* msg.
|
||||
*
|
||||
* \param[in] runtime_individual_description the runtime struct to convert
|
||||
* \return the converted individual type description msg
|
||||
*/
|
||||
template<
|
||||
typename ToAllocatorT = std::allocator<void>,
|
||||
typename FromAllocatorT
|
||||
>
|
||||
type_description_interfaces::msg::IndividualTypeDescription_<ToAllocatorT>
|
||||
convert_individual_type_description_runtime_to_msg(
|
||||
const rosidl_runtime_cpp::type_description::IndividualTypeDescription_<FromAllocatorT> &
|
||||
runtime_individual_description, const ToAllocatorT & alloc = ToAllocatorT())
|
||||
{
|
||||
type_description_interfaces::msg::IndividualTypeDescription_<ToAllocatorT> out(alloc);
|
||||
out.type_name = runtime_individual_description.type_name;
|
||||
|
||||
for (const auto & field : runtime_individual_description.fields) {
|
||||
out.fields.emplace_back();
|
||||
out.fields.back().name = field.name;
|
||||
out.fields.back().default_value = field.default_value;
|
||||
|
||||
out.fields.back().type.type_id = field.type.type_id;
|
||||
out.fields.back().type.capacity = field.type.capacity;
|
||||
out.fields.back().type.string_capacity = field.type.string_capacity;
|
||||
out.fields.back().type.nested_type_name = field.type.nested_type_name;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Convert a individual type description message to its corresponding runtime struct.
|
||||
/**
|
||||
* This function converts a type_description_interfaces/msg/IndividualTypeDescription msg
|
||||
* to the corresponding rosidl_runtime_cpp::type_description::IndividualTypeDescription
|
||||
* struct.
|
||||
*
|
||||
* \param[in] description_msg the message to convert
|
||||
* \return the converted runtime struct
|
||||
*/
|
||||
template<
|
||||
typename ToAllocatorT = std::allocator<void>,
|
||||
typename FromAllocatorT
|
||||
>
|
||||
rosidl_runtime_cpp::type_description::IndividualTypeDescription_<ToAllocatorT>
|
||||
convert_individual_type_description_msg_to_runtime(
|
||||
const type_description_interfaces::msg::IndividualTypeDescription_<FromAllocatorT> &
|
||||
individual_description_msg, const ToAllocatorT & alloc = ToAllocatorT())
|
||||
{
|
||||
rosidl_runtime_cpp::type_description::IndividualTypeDescription_<ToAllocatorT> out(alloc);
|
||||
out.type_name = individual_description_msg.type_name;
|
||||
|
||||
for (const auto & field : individual_description_msg.fields) {
|
||||
out.fields.emplace_back();
|
||||
out.fields.back().name = field.name;
|
||||
out.fields.back().default_value = field.default_value;
|
||||
|
||||
out.fields.back().type.type_id = field.type.type_id;
|
||||
out.fields.back().type.capacity = field.type.capacity;
|
||||
out.fields.back().type.string_capacity = field.type.string_capacity;
|
||||
out.fields.back().type.nested_type_name = field.type.nested_type_name;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// TypeDescription =================================================================================
|
||||
|
||||
/// Convert a runtime type description struct to its corresponding message.
|
||||
/**
|
||||
* This function converts a rosidl_runtime_cpp::type_description::TypeDescription
|
||||
* struct to the corresponding type_description_interfaces/msg/TypeDescription
|
||||
* msg.
|
||||
*
|
||||
* \param[in] runtime_description the runtime struct to convert
|
||||
* \return the converted message
|
||||
*/
|
||||
template<
|
||||
typename ToAllocatorT = std::allocator<void>,
|
||||
typename FromAllocatorT
|
||||
>
|
||||
type_description_interfaces::msg::TypeDescription_<ToAllocatorT>
|
||||
convert_type_description_runtime_to_msg(
|
||||
const rosidl_runtime_cpp::type_description::TypeDescription_<FromAllocatorT> & runtime_description,
|
||||
const ToAllocatorT & alloc = ToAllocatorT())
|
||||
{
|
||||
type_description_interfaces::msg::TypeDescription_<ToAllocatorT> out(alloc);
|
||||
out.type_description =
|
||||
convert_individual_type_description_runtime_to_msg(runtime_description.type_description, alloc);
|
||||
|
||||
for (const auto & referenced_type_description :
|
||||
runtime_description.referenced_type_descriptions)
|
||||
{
|
||||
out.referenced_type_descriptions.push_back(convert_individual_type_description_runtime_to_msg(
|
||||
referenced_type_description, alloc));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Convert a type description message to its corresponding runtime struct.
|
||||
/**
|
||||
* This function converts a type_description_interfaces/msg/TypeDescription msg
|
||||
* to the corresponding rosidl_runtime_cpp::type_description::TypeDescription
|
||||
* struct.
|
||||
*
|
||||
* \param[in] description_msg the message to convert
|
||||
* \return the converted runtime struct
|
||||
*/
|
||||
template<
|
||||
typename ToAllocatorT = std::allocator<void>,
|
||||
typename FromAllocatorT
|
||||
>
|
||||
rosidl_runtime_cpp::type_description::TypeDescription_<ToAllocatorT>
|
||||
convert_type_description_msg_to_runtime(
|
||||
const type_description_interfaces::msg::TypeDescription_<FromAllocatorT> & description_msg,
|
||||
const ToAllocatorT & alloc = ToAllocatorT())
|
||||
{
|
||||
rosidl_runtime_cpp::type_description::TypeDescription_<ToAllocatorT> out(alloc);
|
||||
out.type_description =
|
||||
convert_individual_type_description_msg_to_runtime(description_msg.type_description, alloc);
|
||||
|
||||
for (const auto & referenced_type_description : description_msg.referenced_type_descriptions) {
|
||||
out.referenced_type_descriptions.push_back(convert_individual_type_description_msg_to_runtime(
|
||||
referenced_type_description, alloc));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// TypeSource ======================================================================================
|
||||
|
||||
/// Convert a runtime type source struct to its corresponding message.
|
||||
/**
|
||||
* This function converts a rosidl_runtime_cpp::type_description::TypeSource
|
||||
* struct to the corresponding type_description_interfaces/msg/TypeSource msg.
|
||||
*
|
||||
* \param[in] runtime_type_source the runtime struct to convert
|
||||
* \return the converted message
|
||||
*/
|
||||
template<
|
||||
typename ToAllocatorT = std::allocator<void>,
|
||||
typename FromAllocatorT
|
||||
>
|
||||
type_description_interfaces::msg::TypeSource_<ToAllocatorT>
|
||||
convert_type_source_sequence_runtime_to_msg(
|
||||
const rosidl_runtime_cpp::type_description::TypeSource_<FromAllocatorT> & runtime_type_source,
|
||||
const ToAllocatorT & alloc = ToAllocatorT())
|
||||
{
|
||||
type_description_interfaces::msg::TypeSource_<ToAllocatorT> out(alloc);
|
||||
out.type_name = runtime_type_source.type_name;
|
||||
out.encoding = runtime_type_source.encoding;
|
||||
out.raw_file_contents = runtime_type_source.raw_file_contents;
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Convert a type source message to its corresponding runtime struct.
|
||||
/**
|
||||
* This function converts a type_description_interfaces/msg/TypeSource msg to
|
||||
* the corresponding rosidl_runtime_cpp::type_description::TypeSource struct.
|
||||
*
|
||||
* \param[in] type_source_msg the message to convert
|
||||
* \return the converted runtime struct
|
||||
*/
|
||||
template<
|
||||
typename ToAllocatorT = std::allocator<void>,
|
||||
typename FromAllocatorT
|
||||
>
|
||||
rosidl_runtime_cpp::type_description::TypeSource_<ToAllocatorT>
|
||||
convert_type_source_sequence_msg_to_runtime(
|
||||
const type_description_interfaces::msg::TypeSource_<FromAllocatorT> & type_source_msg,
|
||||
const ToAllocatorT & alloc = ToAllocatorT())
|
||||
{
|
||||
rosidl_runtime_cpp::type_description::TypeSource_<ToAllocatorT> out(alloc);
|
||||
out.type_name = type_source_msg.type_name;
|
||||
out.encoding = type_source_msg.encoding;
|
||||
out.raw_file_contents = type_source_msg.raw_file_contents;
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace dynamic_typesupport
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__TYPE_DESCRIPTION_CONVERSIONS_HPP_
|
||||
@@ -1430,7 +1430,7 @@ public:
|
||||
rclcpp::Clock::ConstSharedPtr
|
||||
get_clock() const;
|
||||
|
||||
/// Returns current time from the time source specified by clock_type.
|
||||
/// Returns current time from the node clock.
|
||||
/**
|
||||
* \sa rclcpp::Clock::now
|
||||
*/
|
||||
|
||||
@@ -146,8 +146,7 @@ public:
|
||||
const rclcpp::QoS & qos,
|
||||
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
|
||||
{
|
||||
// Topic is unused for now.
|
||||
(void)topic;
|
||||
(void)qos;
|
||||
(void)options;
|
||||
|
||||
// If needed, setup intra process communication.
|
||||
@@ -155,22 +154,26 @@ public:
|
||||
auto context = node_base->get_context();
|
||||
// Get the intra process manager instance for this context.
|
||||
auto ipm = context->get_sub_context<rclcpp::experimental::IntraProcessManager>();
|
||||
// Register the publisher with the intra process manager.
|
||||
if (qos.history() != rclcpp::HistoryPolicy::KeepLast) {
|
||||
// Check if the QoS is compatible with intra-process.
|
||||
auto qos_profile = get_actual_qos();
|
||||
if (qos_profile.history() != rclcpp::HistoryPolicy::KeepLast) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication allowed only with keep last history qos policy");
|
||||
"intraprocess communication on topic '" + topic +
|
||||
"' allowed only with keep last history qos policy");
|
||||
}
|
||||
if (qos.depth() == 0) {
|
||||
if (qos_profile.depth() == 0) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication is not allowed with a zero qos history depth value");
|
||||
"intraprocess communication on topic '" + topic +
|
||||
"' is not allowed with a zero qos history depth value");
|
||||
}
|
||||
if (qos.durability() == rclcpp::DurabilityPolicy::TransientLocal) {
|
||||
if (qos_profile.durability() == rclcpp::DurabilityPolicy::TransientLocal) {
|
||||
buffer_ = rclcpp::experimental::create_intra_process_buffer<
|
||||
ROSMessageType, ROSMessageTypeAllocator, ROSMessageTypeDeleter>(
|
||||
rclcpp::detail::resolve_intra_process_buffer_type(options_.intra_process_buffer_type),
|
||||
qos,
|
||||
qos_profile,
|
||||
std::make_shared<ROSMessageTypeAllocator>(ros_message_type_allocator_));
|
||||
}
|
||||
// Register the publisher with the intra process manager.
|
||||
uint64_t intra_process_publisher_id = ipm->add_publisher(this->shared_from_this(), buffer_);
|
||||
this->setup_intra_process(
|
||||
intra_process_publisher_id,
|
||||
@@ -232,8 +235,12 @@ public:
|
||||
// interprocess publish, resulting in lower publish-to-subscribe latency.
|
||||
// It's not possible to do that with an unique_ptr,
|
||||
// as do_intra_process_publish takes the ownership of the message.
|
||||
|
||||
// When durability is set to TransientLocal (i.e. there is a buffer),
|
||||
// inter process publish should always take place to ensure
|
||||
// late joiners receive past data.
|
||||
bool inter_process_publish_needed =
|
||||
get_subscription_count() > get_intra_process_subscription_count();
|
||||
get_subscription_count() > get_intra_process_subscription_count() || buffer_;
|
||||
|
||||
if (inter_process_publish_needed) {
|
||||
auto shared_msg =
|
||||
@@ -310,8 +317,11 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
// When durability is set to TransientLocal (i.e. there is a buffer),
|
||||
// inter process publish should always take place to ensure
|
||||
// late joiners receive past data.
|
||||
bool inter_process_publish_needed =
|
||||
get_subscription_count() > get_intra_process_subscription_count();
|
||||
get_subscription_count() > get_intra_process_subscription_count() || buffer_;
|
||||
|
||||
if (inter_process_publish_needed) {
|
||||
auto ros_msg_ptr = std::make_shared<ROSMessageType>();
|
||||
|
||||
@@ -147,11 +147,13 @@ public:
|
||||
auto qos_profile = get_actual_qos();
|
||||
if (qos_profile.history() != rclcpp::HistoryPolicy::KeepLast) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication allowed only with keep last history qos policy");
|
||||
"intraprocess communication on topic '" + topic_name +
|
||||
"' allowed only with keep last history qos policy");
|
||||
}
|
||||
if (qos_profile.depth() == 0) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication is not allowed with 0 depth qos policy");
|
||||
"intraprocess communication on topic '" + topic_name +
|
||||
"' is not allowed with 0 depth qos policy");
|
||||
}
|
||||
|
||||
using SubscriptionIntraProcessT = rclcpp::experimental::SubscriptionIntraProcess<
|
||||
|
||||
@@ -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>29.2.0</version>
|
||||
<version>29.3.0</version>
|
||||
<description>The ROS client library in C++.</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -729,13 +729,33 @@ Executor::wait_for_work(std::chrono::nanoseconds timeout)
|
||||
// Clear any previous wait result
|
||||
this->wait_result_.reset();
|
||||
|
||||
// we need to make sure that callback groups don't get out of scope
|
||||
// during the wait. As in jazzy, they are not covered by the DynamicStorage,
|
||||
// we explicitly hold them here as a bugfix
|
||||
std::vector<rclcpp::CallbackGroup::SharedPtr> cbgs;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
|
||||
if (this->entities_need_rebuild_.exchange(false) || current_collection_.empty()) {
|
||||
this->collect_entities();
|
||||
}
|
||||
|
||||
auto callback_groups = this->collector_.get_all_callback_groups();
|
||||
cbgs.resize(callback_groups.size());
|
||||
for(const auto & w_ptr : callback_groups) {
|
||||
auto shr_ptr = w_ptr.lock();
|
||||
if(shr_ptr) {
|
||||
cbgs.push_back(std::move(shr_ptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->wait_result_.emplace(wait_set_.wait(timeout));
|
||||
|
||||
// drop references to the callback groups, before trying to execute anything
|
||||
cbgs.clear();
|
||||
|
||||
if (!this->wait_result_ || this->wait_result_->kind() == WaitResultKind::Empty) {
|
||||
RCUTILS_LOG_WARN_NAMED(
|
||||
"rclcpp",
|
||||
|
||||
@@ -110,10 +110,29 @@ StaticSingleThreadedExecutor::spin_once_impl(std::chrono::nanoseconds timeout)
|
||||
std::optional<rclcpp::WaitResult<rclcpp::WaitSet>>
|
||||
StaticSingleThreadedExecutor::collect_and_wait(std::chrono::nanoseconds timeout)
|
||||
{
|
||||
// we need to make sure that callback groups don't get out of scope
|
||||
// during the wait. As in jazzy, they are not covered by the DynamicStorage,
|
||||
// we explicitly hold them here as a bugfix
|
||||
std::vector<rclcpp::CallbackGroup::SharedPtr> cbgs;
|
||||
|
||||
if (this->entities_need_rebuild_.exchange(false) || current_collection_.empty()) {
|
||||
this->collect_entities();
|
||||
}
|
||||
|
||||
auto callback_groups = this->collector_.get_all_callback_groups();
|
||||
cbgs.resize(callback_groups.size());
|
||||
for(const auto & w_ptr : callback_groups) {
|
||||
auto shr_ptr = w_ptr.lock();
|
||||
if(shr_ptr) {
|
||||
cbgs.push_back(std::move(shr_ptr));
|
||||
}
|
||||
}
|
||||
|
||||
auto wait_result = wait_set_.wait(std::chrono::nanoseconds(timeout));
|
||||
|
||||
// drop references to the callback groups, before trying to execute anything
|
||||
cbgs.clear();
|
||||
|
||||
if (wait_result.kind() == WaitResultKind::Empty) {
|
||||
RCUTILS_LOG_WARN_NAMED(
|
||||
"rclcpp",
|
||||
|
||||
@@ -28,6 +28,13 @@ ament_add_gtest(
|
||||
if(TARGET test_allocator_deleter)
|
||||
target_link_libraries(test_allocator_deleter ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_type_description_conversions
|
||||
dynamic_typesupport/test_type_description_conversions.cpp)
|
||||
if(TARGET test_type_description_conversions)
|
||||
target_link_libraries(test_type_description_conversions ${PROJECT_NAME} ${rcl_interfaces_TARGETS})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(
|
||||
test_exceptions
|
||||
exceptions/test_exceptions.cpp)
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
// Copyright 2025 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "rclcpp/dynamic_typesupport/type_description_conversions.hpp"
|
||||
#include "rosidl_runtime_cpp/type_description/individual_type_description__struct.hpp"
|
||||
#include "rosidl_runtime_cpp/type_description/type_description__struct.hpp"
|
||||
#include "rosidl_runtime_cpp/type_description/type_source__struct.hpp"
|
||||
#include "type_description_interfaces/msg/individual_type_description.hpp"
|
||||
#include "type_description_interfaces/msg/type_description.hpp"
|
||||
#include "type_description_interfaces/msg/type_source.hpp"
|
||||
|
||||
using rclcpp::dynamic_typesupport::
|
||||
convert_individual_type_description_msg_to_runtime;
|
||||
using rclcpp::dynamic_typesupport::
|
||||
convert_individual_type_description_runtime_to_msg;
|
||||
using rclcpp::dynamic_typesupport::convert_type_description_msg_to_runtime;
|
||||
using rclcpp::dynamic_typesupport::convert_type_description_runtime_to_msg;
|
||||
using rclcpp::dynamic_typesupport::convert_type_source_sequence_msg_to_runtime;
|
||||
using rclcpp::dynamic_typesupport::convert_type_source_sequence_runtime_to_msg;
|
||||
|
||||
TEST(TestTypeDescriptionConversions, individual_type_description_roundtrip)
|
||||
{
|
||||
rosidl_runtime_cpp::type_description::IndividualTypeDescription original;
|
||||
original.type_name = "test_type_name";
|
||||
|
||||
original.fields.emplace_back();
|
||||
original.fields.back().name = "field1";
|
||||
original.fields.back().type.type_id = 1;
|
||||
|
||||
original.fields.emplace_back();
|
||||
original.fields.back().name = "field2";
|
||||
original.fields.back().type.type_id = 2;
|
||||
|
||||
type_description_interfaces::msg::IndividualTypeDescription msg =
|
||||
convert_individual_type_description_runtime_to_msg(original);
|
||||
rosidl_runtime_cpp::type_description::IndividualTypeDescription converted_back
|
||||
=
|
||||
convert_individual_type_description_msg_to_runtime(msg);
|
||||
|
||||
EXPECT_EQ(original.type_name, converted_back.type_name);
|
||||
ASSERT_EQ(original.fields.size(), converted_back.fields.size());
|
||||
for (size_t i = 0; i < original.fields.size(); ++i) {
|
||||
EXPECT_EQ(original.fields[i].name, converted_back.fields[i].name);
|
||||
EXPECT_EQ(original.fields[i].type, converted_back.fields[i].type);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestTypeDescriptionConversions, type_description_roundtrip)
|
||||
{
|
||||
rosidl_runtime_cpp::type_description::TypeDescription original;
|
||||
original.type_description.type_name = "main_type";
|
||||
original.type_description.fields.emplace_back();
|
||||
original.type_description.fields.back().name = "field1";
|
||||
original.type_description.fields.back().type.type_id = 1;
|
||||
original.type_description.fields.emplace_back();
|
||||
original.type_description.fields.back().name = "field2";
|
||||
original.type_description.fields.back().type.type_id = 2;
|
||||
|
||||
rosidl_runtime_cpp::type_description::IndividualTypeDescription ref1;
|
||||
ref1.type_name = "ref_type_1";
|
||||
ref1.fields.emplace_back();
|
||||
ref1.fields.back().name = "ref_field1";
|
||||
ref1.fields.back().type.type_id = 1;
|
||||
|
||||
rosidl_runtime_cpp::type_description::IndividualTypeDescription ref2;
|
||||
ref2.type_name = "ref_type_2";
|
||||
ref2.fields.emplace_back();
|
||||
ref2.fields.back().name = "ref_field2";
|
||||
ref2.fields.back().type.type_id = 2;
|
||||
|
||||
original.referenced_type_descriptions.push_back(ref1);
|
||||
original.referenced_type_descriptions.push_back(ref2);
|
||||
|
||||
type_description_interfaces::msg::TypeDescription msg =
|
||||
convert_type_description_runtime_to_msg(original);
|
||||
rosidl_runtime_cpp::type_description::TypeDescription converted_back =
|
||||
convert_type_description_msg_to_runtime(msg);
|
||||
|
||||
EXPECT_EQ(original.type_description.type_name,
|
||||
converted_back.type_description.type_name);
|
||||
ASSERT_EQ(original.referenced_type_descriptions.size(),
|
||||
converted_back.referenced_type_descriptions.size());
|
||||
|
||||
for (size_t i = 0; i < original.referenced_type_descriptions.size(); ++i) {
|
||||
EXPECT_EQ(original.referenced_type_descriptions[i].type_name,
|
||||
converted_back.referenced_type_descriptions[i].type_name);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestTypeSourceConversions, type_source_roundtrip)
|
||||
{
|
||||
rosidl_runtime_cpp::type_description::TypeSource original;
|
||||
original.type_name = "test_type_name";
|
||||
original.encoding = "test_encoding";
|
||||
original.raw_file_contents = "test_contents";
|
||||
|
||||
type_description_interfaces::msg::TypeSource msg =
|
||||
convert_type_source_sequence_runtime_to_msg(original);
|
||||
rosidl_runtime_cpp::type_description::TypeSource converted_back =
|
||||
convert_type_source_sequence_msg_to_runtime(msg);
|
||||
|
||||
EXPECT_EQ(original.type_name, converted_back.type_name);
|
||||
EXPECT_EQ(original.encoding, converted_back.encoding);
|
||||
EXPECT_EQ(original.raw_file_contents, converted_back.raw_file_contents);
|
||||
}
|
||||
@@ -388,7 +388,7 @@ to_nanoseconds_helper(DurationT duration)
|
||||
// - works nominally (it can execute entities)
|
||||
// - it can execute multiple items at once
|
||||
// - it does not wait for work to be available before returning
|
||||
TYPED_TEST(TestExecutors, spin_some)
|
||||
TYPED_TEST(TestExecutors, spinSome)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
|
||||
@@ -484,7 +484,7 @@ TYPED_TEST(TestExecutors, spin_some)
|
||||
// do not properly implement max_duration (it seems), so disable this test
|
||||
// for them in the meantime.
|
||||
// see: https://github.com/ros2/rclcpp/issues/2462
|
||||
TYPED_TEST(TestExecutorsStable, spin_some_max_duration)
|
||||
TYPED_TEST(TestExecutorsStable, spinSomeMaxDuration)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
|
||||
@@ -714,6 +714,13 @@ TYPED_TEST(TestExecutors, notifyTwiceWhileSpinning)
|
||||
sub1_msg_count++;
|
||||
});
|
||||
|
||||
// Wait for the subscription to be matched
|
||||
size_t tries = 10000;
|
||||
while (this->publisher->get_subscription_count() < 2 && tries-- > 0) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
ASSERT_EQ(this->publisher->get_subscription_count(), 2);
|
||||
|
||||
// Publish a message and verify it's received
|
||||
this->publisher->publish(test_msgs::msg::Empty());
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
@@ -731,6 +738,13 @@ TYPED_TEST(TestExecutors, notifyTwiceWhileSpinning)
|
||||
sub2_msg_count++;
|
||||
});
|
||||
|
||||
// Wait for the subscription to be matched
|
||||
tries = 10000;
|
||||
while (this->publisher->get_subscription_count() < 3 && tries-- > 0) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
ASSERT_EQ(this->publisher->get_subscription_count(), 3);
|
||||
|
||||
// Publish a message and verify it's received by both subscriptions
|
||||
this->publisher->publish(test_msgs::msg::Empty());
|
||||
start = std::chrono::steady_clock::now();
|
||||
@@ -820,7 +834,7 @@ TEST(TestExecutors, testSpinWithNonDefaultContext)
|
||||
rclcpp::shutdown(non_default_context);
|
||||
}
|
||||
|
||||
TYPED_TEST(TestExecutors, release_ownership_entity_after_spinning_cancel)
|
||||
TYPED_TEST(TestExecutors, releaseOwnershipEntityAfterSpinningCancel)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
ExecutorType executor;
|
||||
@@ -843,3 +857,36 @@ TYPED_TEST(TestExecutors, release_ownership_entity_after_spinning_cancel)
|
||||
|
||||
EXPECT_EQ(server.use_count(), 1);
|
||||
}
|
||||
|
||||
TYPED_TEST(TestExecutors, testRaceDropCallbackGroupFromSecondThread)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
|
||||
// Create an executor
|
||||
ExecutorType executor;
|
||||
executor.add_node(this->node);
|
||||
|
||||
// Start spinning
|
||||
auto executor_thread = std::thread(
|
||||
[&executor]() {
|
||||
executor.spin();
|
||||
});
|
||||
|
||||
// As the problem is a race, we do this multiple times,
|
||||
// to raise our chances of hitting the problem
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
auto cg = this->node->create_callback_group(
|
||||
rclcpp::CallbackGroupType::MutuallyExclusive);
|
||||
auto timer = this->node->create_timer(1s, [] {}, cg);
|
||||
// sleep a bit, so that the spin thread can pick up the callback group
|
||||
// and add it to the executor
|
||||
std::this_thread::sleep_for(5ms);
|
||||
|
||||
// At this point the callbackgroup should be used within the waitset of the executor
|
||||
// as we leave the scope, the reference to cg will be dropped.
|
||||
// If the executor has a race, we will experience a segfault at this point.
|
||||
}
|
||||
|
||||
executor.cancel();
|
||||
executor_thread.join();
|
||||
}
|
||||
|
||||
@@ -431,7 +431,7 @@ TYPED_TEST(TestAllClientTypesWithServer, client_qos)
|
||||
|
||||
rclcpp::ServicesQoS qos_profile;
|
||||
qos_profile.liveliness(rclcpp::LivelinessPolicy::Automatic);
|
||||
rclcpp::Duration duration(std::chrono::nanoseconds(1));
|
||||
rclcpp::Duration duration(std::chrono::milliseconds(1));
|
||||
qos_profile.deadline(duration);
|
||||
qos_profile.lifespan(duration);
|
||||
qos_profile.liveliness_lease_duration(duration);
|
||||
|
||||
@@ -92,3 +92,19 @@ TEST_F(TestCreateSubscription, create_with_statistics) {
|
||||
ASSERT_NE(nullptr, subscription);
|
||||
EXPECT_STREQ("/ns/topic_name", subscription->get_topic_name());
|
||||
}
|
||||
|
||||
TEST_F(TestCreateSubscription, create_with_intra_process_com) {
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
auto options = rclcpp::SubscriptionOptions();
|
||||
options.use_intra_process_comm = rclcpp::IntraProcessSetting::Enable;
|
||||
|
||||
auto callback = [](test_msgs::msg::Empty::ConstSharedPtr) {};
|
||||
rclcpp::Subscription<test_msgs::msg::Empty>::SharedPtr subscription;
|
||||
ASSERT_NO_THROW(
|
||||
{
|
||||
subscription = rclcpp::create_subscription<test_msgs::msg::Empty>(
|
||||
node, "topic_name", rclcpp::SystemDefaultsQoS(), callback, options);
|
||||
});
|
||||
ASSERT_NE(nullptr, subscription);
|
||||
EXPECT_STREQ("/ns/topic_name", subscription->get_topic_name());
|
||||
}
|
||||
|
||||
@@ -320,7 +320,7 @@ TEST_F(TestGenericService, rcl_service_request_subscription_get_actual_qos_error
|
||||
TEST_F(TestGenericService, generic_service_qos) {
|
||||
rclcpp::ServicesQoS qos_profile;
|
||||
qos_profile.liveliness(rclcpp::LivelinessPolicy::Automatic);
|
||||
rclcpp::Duration duration(std::chrono::nanoseconds(1));
|
||||
rclcpp::Duration duration(std::chrono::milliseconds(1));
|
||||
qos_profile.deadline(duration);
|
||||
qos_profile.lifespan(duration);
|
||||
qos_profile.liveliness_lease_duration(duration);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <future>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -187,6 +188,21 @@ TEST_F(TestPublisher, various_creation_signatures) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Testing publisher with intraprocess enabled and SystemDefaultQoS
|
||||
*/
|
||||
TEST_F(TestPublisher, test_publisher_with_system_default_qos) {
|
||||
initialize(rclcpp::NodeOptions().use_intra_process_comms(false));
|
||||
// explicitly enable intra-process comm with publisher option
|
||||
auto options = rclcpp::PublisherOptions();
|
||||
options.use_intra_process_comm = rclcpp::IntraProcessSetting::Enable;
|
||||
using test_msgs::msg::Empty;
|
||||
ASSERT_NO_THROW(
|
||||
{
|
||||
auto publisher = node->create_publisher<Empty>("topic", rclcpp::SystemDefaultsQoS());
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
Testing publisher with intraprocess enabled and invalid QoS
|
||||
*/
|
||||
@@ -432,11 +448,10 @@ TEST_F(TestPublisher, intra_process_publish_failures) {
|
||||
publisher->get_publisher_handle().get(), msg.get()));
|
||||
}
|
||||
}
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
node->create_publisher<test_msgs::msg::Empty>(
|
||||
"topic", rclcpp::QoS(0), options),
|
||||
std::invalid_argument(
|
||||
"intraprocess communication is not allowed with a zero qos history depth value"));
|
||||
// a zero depth with KEEP_LAST doesn't make sense,
|
||||
// this will be interpreted as SystemDefaultQoS by rclcpp.
|
||||
EXPECT_NO_THROW(
|
||||
node->create_publisher<test_msgs::msg::Empty>("topic", rclcpp::QoS(0), options));
|
||||
}
|
||||
|
||||
TEST_F(TestPublisher, inter_process_publish_failures) {
|
||||
@@ -711,11 +726,7 @@ TEST_F(TestPublisher, intra_process_transient_local) {
|
||||
auto do_nothing = [](std::shared_ptr<const test_msgs::msg::Empty>) {};
|
||||
struct IntraProcessCallback
|
||||
{
|
||||
void callback_fun(size_t s)
|
||||
{
|
||||
(void) s;
|
||||
called = true;
|
||||
}
|
||||
void callback_fun(size_t) {called = true;}
|
||||
bool called = false;
|
||||
};
|
||||
rclcpp::SubscriptionOptions sub_options_ipm_disabled;
|
||||
@@ -772,3 +783,44 @@ TEST_F(TestPublisher, intra_process_transient_local) {
|
||||
EXPECT_FALSE(callback3.called);
|
||||
EXPECT_FALSE(callback4.called);
|
||||
}
|
||||
|
||||
TEST_F(TestPublisher, intra_process_inter_process_mix_transient_local) {
|
||||
constexpr auto history_depth = 10u;
|
||||
initialize(rclcpp::NodeOptions().use_intra_process_comms(true));
|
||||
|
||||
rclcpp::PublisherOptionsWithAllocator<std::allocator<void>> pub_options_ipm_enabled;
|
||||
pub_options_ipm_enabled.use_intra_process_comm = rclcpp::IntraProcessSetting::Enable;
|
||||
|
||||
auto pub_ipm_enabled_transient_local_enabled = node->create_publisher<test_msgs::msg::Empty>(
|
||||
"topic1",
|
||||
rclcpp::QoS(rclcpp::KeepLast(history_depth)).transient_local(), pub_options_ipm_enabled);
|
||||
|
||||
test_msgs::msg::Empty msg;
|
||||
pub_ipm_enabled_transient_local_enabled->publish(msg);
|
||||
|
||||
auto do_nothing = [](std::shared_ptr<const test_msgs::msg::Empty>) {};
|
||||
struct SubscriptionCallback
|
||||
{
|
||||
void callback_fun(size_t) {called.set_value();}
|
||||
std::promise<void> called;
|
||||
};
|
||||
rclcpp::SubscriptionOptions sub_options_ipm_disabled;
|
||||
sub_options_ipm_disabled.use_intra_process_comm = rclcpp::IntraProcessSetting::Disable;
|
||||
SubscriptionCallback intra_callback, inter_callback;
|
||||
std::future<void> intra_callback_future = intra_callback.called.get_future(),
|
||||
inter_callback_future = inter_callback.called.get_future();
|
||||
auto sub_ipm_disabled_transient_local_enabled = node->create_subscription<test_msgs::msg::Empty>(
|
||||
"topic1",
|
||||
rclcpp::QoS(rclcpp::KeepLast(history_depth)).transient_local(),
|
||||
do_nothing, sub_options_ipm_disabled);
|
||||
sub_ipm_disabled_transient_local_enabled->set_on_new_intra_process_message_callback(
|
||||
std::bind(&SubscriptionCallback::callback_fun, &intra_callback, std::placeholders::_1));
|
||||
sub_ipm_disabled_transient_local_enabled->set_on_new_message_callback(
|
||||
std::bind(&SubscriptionCallback::callback_fun, &inter_callback, std::placeholders::_1));
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
EXPECT_EQ(executor.spin_until_future_complete(inter_callback_future,
|
||||
std::chrono::milliseconds(100)), rclcpp::FutureReturnCode::SUCCESS);
|
||||
EXPECT_EQ(executor.spin_until_future_complete(intra_callback_future,
|
||||
std::chrono::milliseconds(100)), rclcpp::FutureReturnCode::TIMEOUT);
|
||||
}
|
||||
|
||||
@@ -335,7 +335,7 @@ TEST_F(TestService, rcl_service_request_subscription_get_actual_qos_error) {
|
||||
TEST_F(TestService, server_qos) {
|
||||
rclcpp::ServicesQoS qos_profile;
|
||||
qos_profile.liveliness(rclcpp::LivelinessPolicy::Automatic);
|
||||
rclcpp::Duration duration(std::chrono::nanoseconds(1));
|
||||
rclcpp::Duration duration(std::chrono::milliseconds(1));
|
||||
qos_profile.deadline(duration);
|
||||
qos_profile.lifespan(duration);
|
||||
qos_profile.liveliness_lease_duration(duration);
|
||||
|
||||
@@ -92,9 +92,16 @@ TEST_F(TestServiceIntrospection, service_introspection_nominal)
|
||||
request->set__int64_value(42);
|
||||
|
||||
client->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
|
||||
service->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
|
||||
|
||||
// Wait for the introspection to attach to our subscription
|
||||
size_t tries = 1000;
|
||||
while (this->sub->get_publisher_count() < 2 && tries-- > 0) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
ASSERT_EQ(sub->get_publisher_count(), 2u);
|
||||
|
||||
auto future = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
@@ -163,9 +170,11 @@ TEST_F(TestServiceIntrospection, service_introspection_nominal)
|
||||
TEST_F(TestServiceIntrospection, service_introspection_enable_disable_events)
|
||||
{
|
||||
client->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_OFF);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_OFF);
|
||||
service->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_OFF);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_OFF);
|
||||
|
||||
ASSERT_EQ(sub->get_publisher_count(), 0);
|
||||
|
||||
auto request = std::make_shared<BasicTypes::Request>();
|
||||
request->set__bool_value(true);
|
||||
@@ -183,9 +192,16 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_events)
|
||||
events.clear();
|
||||
|
||||
client->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
|
||||
service->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_OFF);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_OFF);
|
||||
|
||||
// Wait for the introspection to attach to our subscription
|
||||
size_t tries = 1000;
|
||||
while (this->sub->get_publisher_count() < 1 && tries-- > 0) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
ASSERT_EQ(sub->get_publisher_count(), 1u);
|
||||
|
||||
future = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
@@ -200,9 +216,16 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_events)
|
||||
events.clear();
|
||||
|
||||
client->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_OFF);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_OFF);
|
||||
service->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
|
||||
|
||||
// Wait for the introspection to attach to our subscription
|
||||
tries = 1000;
|
||||
while (this->sub->get_publisher_count() < 1 && tries-- > 0) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
ASSERT_EQ(sub->get_publisher_count(), 1u);
|
||||
|
||||
future = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
@@ -217,9 +240,16 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_events)
|
||||
events.clear();
|
||||
|
||||
client->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
|
||||
service->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
|
||||
|
||||
// Wait for the introspection to attach to our subscription
|
||||
tries = 1000;
|
||||
while (this->sub->get_publisher_count() < 2 && tries-- > 0) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
ASSERT_EQ(sub->get_publisher_count(), 2u);
|
||||
|
||||
future = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
@@ -235,9 +265,16 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_events)
|
||||
TEST_F(TestServiceIntrospection, service_introspection_enable_disable_event_content)
|
||||
{
|
||||
client->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
|
||||
service->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
|
||||
|
||||
// Wait for the introspection to attach to our subscription
|
||||
size_t tries = 1000;
|
||||
while (this->sub->get_publisher_count() < 2 && tries-- > 0) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
ASSERT_EQ(sub->get_publisher_count(), 2u);
|
||||
|
||||
auto request = std::make_shared<BasicTypes::Request>();
|
||||
request->set__bool_value(true);
|
||||
@@ -259,9 +296,16 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_event_cont
|
||||
events.clear();
|
||||
|
||||
client->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
|
||||
service->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
|
||||
|
||||
// Wait for the introspection to attach to our subscription
|
||||
tries = 1000;
|
||||
while (this->sub->get_publisher_count() < 2 && tries-- > 0) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
ASSERT_EQ(sub->get_publisher_count(), 2u);
|
||||
|
||||
future = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
@@ -292,9 +336,16 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_event_cont
|
||||
events.clear();
|
||||
|
||||
client->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
|
||||
service->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
|
||||
|
||||
// Wait for the introspection to attach to our subscription
|
||||
tries = 1000;
|
||||
while (this->sub->get_publisher_count() < 2 && tries-- > 0) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
ASSERT_EQ(sub->get_publisher_count(), 2u);
|
||||
|
||||
future = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
@@ -325,9 +376,16 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_event_cont
|
||||
events.clear();
|
||||
|
||||
client->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
|
||||
service->configure_introspection(
|
||||
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
|
||||
|
||||
// Wait for the introspection to attach to our subscription
|
||||
tries = 1000;
|
||||
while (this->sub->get_publisher_count() < 2 && tries-- > 0) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
ASSERT_EQ(sub->get_publisher_count(), 2u);
|
||||
|
||||
future = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
|
||||
@@ -212,6 +212,9 @@ TEST_F(TestTimeSource, ROS_time_valid_attach_detach) {
|
||||
ts.attachNode(node);
|
||||
EXPECT_FALSE(ros_clock->ros_time_is_active());
|
||||
|
||||
ts.attachClock(ros_clock);
|
||||
EXPECT_FALSE(ros_clock->ros_time_is_active());
|
||||
|
||||
ts.detachClock(ros_clock);
|
||||
EXPECT_FALSE(ros_clock->ros_time_is_active());
|
||||
}
|
||||
|
||||
@@ -3,6 +3,11 @@ Changelog for package rclcpp_action
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
29.3.0 (2024-12-20)
|
||||
-------------------
|
||||
* Make ament_cmake a buildtool dependency (`#2689 <https://github.com/ros2/rclcpp/issues/2689>`_)
|
||||
* Contributors: Nathan Wiebe Neufeldt
|
||||
|
||||
29.2.0 (2024-11-25)
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -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>29.2.0</version>
|
||||
<version>29.3.0</version>
|
||||
<description>Adds action APIs for C++.</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
@@ -26,8 +26,6 @@
|
||||
<depend>rcl</depend>
|
||||
<depend>rcpputils</depend>
|
||||
|
||||
<depend>ament_cmake</depend>
|
||||
|
||||
<test_depend>ament_cmake_gtest</test_depend>
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>ament_lint_common</test_depend>
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
Changelog for package rclcpp_components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
29.3.0 (2024-12-20)
|
||||
-------------------
|
||||
* Add parsing for rest of obvious boolean extra arguments and throw for unsupported ones (`#2685 <https://github.com/ros2/rclcpp/issues/2685>`_)
|
||||
* Contributors: rcp1
|
||||
|
||||
29.2.0 (2024-11-25)
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -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>29.2.0</version>
|
||||
<version>29.3.0</version>
|
||||
<description>Package containing tools for dynamically loadable components</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -169,24 +169,63 @@ ComponentManager::create_node_options(const std::shared_ptr<LoadNode::Request> r
|
||||
|
||||
for (const auto & a : request->extra_arguments) {
|
||||
const rclcpp::Parameter extra_argument = rclcpp::Parameter::from_parameter_msg(a);
|
||||
if (extra_argument.get_name() == "use_intra_process_comms") {
|
||||
if (extra_argument.get_name() == "forward_global_arguments") {
|
||||
if (extra_argument.get_type() != rclcpp::ParameterType::PARAMETER_BOOL) {
|
||||
throw ComponentManagerException(
|
||||
"Extra component argument 'use_intra_process_comms' must be a boolean");
|
||||
}
|
||||
options.use_intra_process_comms(extra_argument.get_value<bool>());
|
||||
} else if (extra_argument.get_name() == "forward_global_arguments") {
|
||||
if (extra_argument.get_type() != rclcpp::ParameterType::PARAMETER_BOOL) {
|
||||
throw ComponentManagerException(
|
||||
"Extra component argument 'forward_global_arguments' must be a boolean");
|
||||
"Extra component argument 'forward_global_arguments' must be a boolean");
|
||||
}
|
||||
options.use_global_arguments(extra_argument.get_value<bool>());
|
||||
if (extra_argument.get_value<bool>()) {
|
||||
RCLCPP_WARN(
|
||||
get_logger(), "forward_global_arguments is true by default in nodes, but is not "
|
||||
"recommended in a component manager. If true, this will cause this node's behavior "
|
||||
"to be influenced by global arguments, not only those targeted at this node.");
|
||||
get_logger(), "forward_global_arguments is true by default in nodes, but is not "
|
||||
"recommended in a component manager. If true, this will cause this node's behavior "
|
||||
"to be influenced by global arguments, not only those targeted at this node.");
|
||||
}
|
||||
} else if (extra_argument.get_name() == "enable_rosout") {
|
||||
if (extra_argument.get_type() != rclcpp::ParameterType::PARAMETER_BOOL) {
|
||||
throw ComponentManagerException(
|
||||
"Extra component argument 'enable_rosout' must be a boolean");
|
||||
}
|
||||
options.enable_rosout(extra_argument.get_value<bool>());
|
||||
} else if (extra_argument.get_name() == "use_intra_process_comms") {
|
||||
if (extra_argument.get_type() != rclcpp::ParameterType::PARAMETER_BOOL) {
|
||||
throw ComponentManagerException(
|
||||
"Extra component argument 'use_intra_process_comms' must be a boolean");
|
||||
}
|
||||
options.use_intra_process_comms(extra_argument.get_value<bool>());
|
||||
} else if (extra_argument.get_name() == "enable_topic_statistics") {
|
||||
if (extra_argument.get_type() != rclcpp::ParameterType::PARAMETER_BOOL) {
|
||||
throw ComponentManagerException(
|
||||
"Extra component argument 'enable_topic_statistics' must be a boolean");
|
||||
}
|
||||
options.enable_topic_statistics(extra_argument.get_value<bool>());
|
||||
} else if (extra_argument.get_name() == "start_parameter_services") {
|
||||
if (extra_argument.get_type() != rclcpp::ParameterType::PARAMETER_BOOL) {
|
||||
throw ComponentManagerException(
|
||||
"Extra component argument 'start_parameter_services' must be a boolean");
|
||||
}
|
||||
options.start_parameter_services(extra_argument.get_value<bool>());
|
||||
} else if (extra_argument.get_name() == "start_parameter_event_publisher") {
|
||||
if (extra_argument.get_type() != rclcpp::ParameterType::PARAMETER_BOOL) {
|
||||
throw ComponentManagerException(
|
||||
"Extra component argument 'start_parameter_event_publisher' must be a boolean");
|
||||
}
|
||||
options.start_parameter_event_publisher(extra_argument.get_value<bool>());
|
||||
} else if (extra_argument.get_name() == "use_clock_thread") {
|
||||
if (extra_argument.get_type() != rclcpp::ParameterType::PARAMETER_BOOL) {
|
||||
throw ComponentManagerException(
|
||||
"Extra component argument 'use_clock_thread' must be a boolean");
|
||||
}
|
||||
options.use_clock_thread(extra_argument.get_value<bool>());
|
||||
} else if (extra_argument.get_name() == "enable_logger_service") {
|
||||
if (extra_argument.get_type() != rclcpp::ParameterType::PARAMETER_BOOL) {
|
||||
throw ComponentManagerException(
|
||||
"Extra component argument 'enable_logger_service' must be a boolean");
|
||||
}
|
||||
options.enable_logger_service(extra_argument.get_value<bool>());
|
||||
} else {
|
||||
throw ComponentManagerException("Extra component argument '" + extra_argument.get_name() +
|
||||
"' is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -181,90 +181,74 @@ void test_components_api(bool use_dedicated_executor)
|
||||
}
|
||||
|
||||
{
|
||||
// use_intra_process_comms
|
||||
// invalid extra argument
|
||||
auto request = std::make_shared<composition_interfaces::srv::LoadNode::Request>();
|
||||
request->package_name = "rclcpp_components";
|
||||
request->plugin_name = "test_rclcpp_components::TestComponentFoo";
|
||||
request->node_name = "test_component_intra_process";
|
||||
rclcpp::Parameter use_intraprocess_comms("use_intra_process_comms",
|
||||
rclcpp::ParameterValue(true));
|
||||
request->extra_arguments.push_back(use_intraprocess_comms.to_parameter_msg());
|
||||
request->node_name = "test_component_allow_undeclared_parameters";
|
||||
rclcpp::Parameter extra_argument("allow_undeclared_parameters", rclcpp::ParameterValue(true));
|
||||
request->extra_arguments.push_back(extra_argument.to_parameter_msg());
|
||||
|
||||
auto future = composition_client->async_send_request(request);
|
||||
auto ret = exec->spin_until_future_complete(future, 5s); // Wait for the result.
|
||||
auto result = future.get();
|
||||
EXPECT_EQ(ret, rclcpp::FutureReturnCode::SUCCESS);
|
||||
EXPECT_EQ(result->success, true);
|
||||
EXPECT_EQ(result->error_message, "");
|
||||
std::cout << result->full_node_name << std::endl;
|
||||
EXPECT_EQ(result->full_node_name, "/test_component_intra_process");
|
||||
EXPECT_EQ(result->unique_id, 6u);
|
||||
}
|
||||
|
||||
{
|
||||
// use_intra_process_comms is not a bool type parameter
|
||||
auto request = std::make_shared<composition_interfaces::srv::LoadNode::Request>();
|
||||
request->package_name = "rclcpp_components";
|
||||
request->plugin_name = "test_rclcpp_components::TestComponentFoo";
|
||||
request->node_name = "test_component_intra_process_str";
|
||||
|
||||
rclcpp::Parameter use_intraprocess_comms("use_intra_process_comms",
|
||||
rclcpp::ParameterValue("hello"));
|
||||
request->extra_arguments.push_back(use_intraprocess_comms.to_parameter_msg());
|
||||
|
||||
auto future = composition_client->async_send_request(request);
|
||||
auto ret = exec->spin_until_future_complete(future, 5s); // Wait for the result.
|
||||
auto ret = exec->spin_until_future_complete(future, 5s); // Wait for the result.
|
||||
auto result = future.get();
|
||||
EXPECT_EQ(ret, rclcpp::FutureReturnCode::SUCCESS);
|
||||
EXPECT_EQ(result->success, false);
|
||||
EXPECT_EQ(
|
||||
result->error_message,
|
||||
"Extra component argument 'use_intra_process_comms' must be a boolean");
|
||||
EXPECT_EQ(result->error_message,
|
||||
"Extra component argument 'allow_undeclared_parameters' is not supported");
|
||||
EXPECT_EQ(result->full_node_name, "");
|
||||
EXPECT_EQ(result->unique_id, 0u);
|
||||
}
|
||||
|
||||
{
|
||||
// forward_global_arguments
|
||||
std::array<std::string, 8u> valid_extra_arguments = {
|
||||
"forward_global_arguments",
|
||||
"use_intra_process_comms",
|
||||
"enable_rosout",
|
||||
"enable_topic_statistics",
|
||||
"start_parameter_services",
|
||||
"start_parameter_event_publisher",
|
||||
"use_clock_thread",
|
||||
"enable_logger_service"
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < valid_extra_arguments.size(); ++i) {
|
||||
const auto & arg = valid_extra_arguments[i];
|
||||
auto request = std::make_shared<composition_interfaces::srv::LoadNode::Request>();
|
||||
request->package_name = "rclcpp_components";
|
||||
request->plugin_name = "test_rclcpp_components::TestComponentFoo";
|
||||
request->node_name = "test_component_global_arguments";
|
||||
rclcpp::Parameter forward_global_arguments("forward_global_arguments",
|
||||
rclcpp::ParameterValue(true));
|
||||
request->extra_arguments.push_back(forward_global_arguments.to_parameter_msg());
|
||||
{
|
||||
// success
|
||||
request->node_name = "test_component_" + arg;
|
||||
rclcpp::Parameter extra_argument(arg, rclcpp::ParameterValue(true));
|
||||
request->extra_arguments.push_back(extra_argument.to_parameter_msg());
|
||||
|
||||
auto future = composition_client->async_send_request(request);
|
||||
auto ret = exec->spin_until_future_complete(future, 5s); // Wait for the result.
|
||||
auto result = future.get();
|
||||
EXPECT_EQ(ret, rclcpp::FutureReturnCode::SUCCESS);
|
||||
EXPECT_EQ(result->success, true);
|
||||
EXPECT_EQ(result->error_message, "");
|
||||
EXPECT_EQ(result->full_node_name, "/test_component_global_arguments");
|
||||
EXPECT_EQ(result->unique_id, 7u);
|
||||
}
|
||||
auto future = composition_client->async_send_request(request);
|
||||
auto ret = exec->spin_until_future_complete(future, 5s); // Wait for the result.
|
||||
auto result = future.get();
|
||||
EXPECT_EQ(ret, rclcpp::FutureReturnCode::SUCCESS);
|
||||
EXPECT_EQ(result->success, true);
|
||||
EXPECT_EQ(result->error_message, "");
|
||||
EXPECT_EQ(result->full_node_name, "/test_component_" + arg);
|
||||
EXPECT_EQ(result->unique_id, 6u + i);
|
||||
}
|
||||
|
||||
{
|
||||
// forward_global_arguments is not a bool type parameter
|
||||
auto request = std::make_shared<composition_interfaces::srv::LoadNode::Request>();
|
||||
request->package_name = "rclcpp_components";
|
||||
request->plugin_name = "test_rclcpp_components::TestComponentFoo";
|
||||
request->node_name = "test_component_global_arguments_str";
|
||||
{
|
||||
// not a bool type parameter
|
||||
request->node_name = "test_component_" + arg + "_str";
|
||||
rclcpp::Parameter extra_argument(arg, rclcpp::ParameterValue("hello"));
|
||||
request->extra_arguments.clear();
|
||||
request->extra_arguments.push_back(extra_argument.to_parameter_msg());
|
||||
|
||||
rclcpp::Parameter forward_global_arguments("forward_global_arguments",
|
||||
rclcpp::ParameterValue("hello"));
|
||||
request->extra_arguments.push_back(forward_global_arguments.to_parameter_msg());
|
||||
|
||||
auto future = composition_client->async_send_request(request);
|
||||
auto ret = exec->spin_until_future_complete(future, 5s); // Wait for the result.
|
||||
auto result = future.get();
|
||||
EXPECT_EQ(ret, rclcpp::FutureReturnCode::SUCCESS);
|
||||
EXPECT_EQ(result->success, false);
|
||||
EXPECT_EQ(
|
||||
result->error_message,
|
||||
"Extra component argument 'forward_global_arguments' must be a boolean");
|
||||
EXPECT_EQ(result->full_node_name, "");
|
||||
EXPECT_EQ(result->unique_id, 0u);
|
||||
auto future = composition_client->async_send_request(request);
|
||||
auto ret = exec->spin_until_future_complete(future, 5s); // Wait for the result.
|
||||
auto result = future.get();
|
||||
EXPECT_EQ(ret, rclcpp::FutureReturnCode::SUCCESS);
|
||||
EXPECT_EQ(result->success, false);
|
||||
EXPECT_EQ(result->error_message,
|
||||
"Extra component argument '" + arg + "' must be a boolean");
|
||||
EXPECT_EQ(result->full_node_name, "");
|
||||
EXPECT_EQ(result->unique_id, 0u);
|
||||
}
|
||||
}
|
||||
|
||||
auto node_names = node->get_node_names();
|
||||
@@ -295,22 +279,19 @@ void test_components_api(bool use_dedicated_executor)
|
||||
auto result_node_names = result->full_node_names;
|
||||
auto result_unique_ids = result->unique_ids;
|
||||
|
||||
EXPECT_EQ(result_node_names.size(), 7u);
|
||||
EXPECT_EQ(result_node_names.size(), 5u + valid_extra_arguments.size());
|
||||
EXPECT_EQ(result_node_names[0], "/test_component_foo");
|
||||
EXPECT_EQ(result_node_names[1], "/test_component_bar");
|
||||
EXPECT_EQ(result_node_names[2], "/test_component_baz");
|
||||
EXPECT_EQ(result_node_names[3], "/ns/test_component_bing");
|
||||
EXPECT_EQ(result_node_names[4], "/test_component_remap");
|
||||
EXPECT_EQ(result_node_names[5], "/test_component_intra_process");
|
||||
EXPECT_EQ(result_node_names[6], "/test_component_global_arguments");
|
||||
EXPECT_EQ(result_unique_ids.size(), 7u);
|
||||
EXPECT_EQ(result_unique_ids[0], 1u);
|
||||
EXPECT_EQ(result_unique_ids[1], 2u);
|
||||
EXPECT_EQ(result_unique_ids[2], 3u);
|
||||
EXPECT_EQ(result_unique_ids[3], 4u);
|
||||
EXPECT_EQ(result_unique_ids[4], 5u);
|
||||
EXPECT_EQ(result_unique_ids[5], 6u);
|
||||
EXPECT_EQ(result_unique_ids[6], 7u);
|
||||
for (size_t i = 0u; i < valid_extra_arguments.size(); ++i) {
|
||||
EXPECT_EQ(result_node_names[5u + i], "/test_component_" + valid_extra_arguments[i]);
|
||||
}
|
||||
EXPECT_EQ(result_unique_ids.size(), 5u + valid_extra_arguments.size());
|
||||
for (size_t i = 0u; i < result_unique_ids.size(); ++i) {
|
||||
EXPECT_EQ(result_unique_ids[i], 1u + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,20 +345,18 @@ void test_components_api(bool use_dedicated_executor)
|
||||
auto result_node_names = result->full_node_names;
|
||||
auto result_unique_ids = result->unique_ids;
|
||||
|
||||
EXPECT_EQ(result_node_names.size(), 6u);
|
||||
EXPECT_EQ(result_node_names.size(), 4u + valid_extra_arguments.size());
|
||||
EXPECT_EQ(result_node_names[0], "/test_component_bar");
|
||||
EXPECT_EQ(result_node_names[1], "/test_component_baz");
|
||||
EXPECT_EQ(result_node_names[2], "/ns/test_component_bing");
|
||||
EXPECT_EQ(result_node_names[3], "/test_component_remap");
|
||||
EXPECT_EQ(result_node_names[4], "/test_component_intra_process");
|
||||
EXPECT_EQ(result_node_names[5], "/test_component_global_arguments");
|
||||
EXPECT_EQ(result_unique_ids.size(), 6u);
|
||||
EXPECT_EQ(result_unique_ids[0], 2u);
|
||||
EXPECT_EQ(result_unique_ids[1], 3u);
|
||||
EXPECT_EQ(result_unique_ids[2], 4u);
|
||||
EXPECT_EQ(result_unique_ids[3], 5u);
|
||||
EXPECT_EQ(result_unique_ids[4], 6u);
|
||||
EXPECT_EQ(result_unique_ids[5], 7u);
|
||||
for (size_t i = 0u; i < valid_extra_arguments.size(); ++i) {
|
||||
EXPECT_EQ(result_node_names[4u + i], "/test_component_" + valid_extra_arguments[i]);
|
||||
}
|
||||
EXPECT_EQ(result_unique_ids.size(), 4u + valid_extra_arguments.size());
|
||||
for (size_t i = 0u; i < result_unique_ids.size(); ++i) {
|
||||
EXPECT_EQ(result_unique_ids[i], 2u + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,11 @@ Changelog for package rclcpp_lifecycle
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
29.3.0 (2024-12-20)
|
||||
-------------------
|
||||
* Update docstring for `rclcpp::Node::now()` (`#2696 <https://github.com/ros2/rclcpp/issues/2696>`_)
|
||||
* Contributors: Patrick Roncagliolo
|
||||
|
||||
29.2.0 (2024-11-25)
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -731,7 +731,7 @@ public:
|
||||
rclcpp::Clock::ConstSharedPtr
|
||||
get_clock() const;
|
||||
|
||||
/// Returns current time from the time source specified by clock_type.
|
||||
/// Returns current time from the node clock.
|
||||
/**
|
||||
* \sa rclcpp::Clock::now
|
||||
*/
|
||||
|
||||
@@ -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>29.2.0</version>
|
||||
<version>29.3.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