Compare commits

...

9 Commits

Author SHA1 Message Date
Tomoya Fujita
546f3ae655 use Reader/Writer lock for Ring Buffer.
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-05-07 10:44:30 -07:00
Alejandro Hernández Cordero
4f507751e1 Removed deprecated rcpputils Path (#2834)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-05-06 00:11:49 +02:00
Alex Youngs
7bd14d812c Add range constraints for applicable array parameters (#2828)
Signed-off-by: Alex Youngs <alexyoungs@hatchbed.com>
2025-05-05 14:39:12 +02:00
Michael Carlstrom
e97d569f75 Update RingBufferImplementation to clear internal data. (#2837)
* Fix clear()

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

* Update rclcpp/include/rclcpp/experimental/buffers/ring_buffer_implementation.hpp

Co-authored-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>

---------

Signed-off-by: Michael Carlstrom <rmc@carlstrom.com>
Co-authored-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
2025-05-04 12:49:21 -07:00
Alejandro Hernández Cordero
f81caaca49 Removed deprecated cancel_sleep_or_wait (#2836)
Signed-off-by: Alejandro Hernandez Cordero <ahcorde@gmail.com>
2025-05-02 15:10:07 +02:00
Tomoya Fujita
127a10e8c8 introduce rcl_lifecycle_get_transition_label_by_id(). (#2827)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-05-01 13:13:05 -07:00
Christophe Bedard
b1ec85df16 Add missing 's' to 'NodeParametersInterface' in doc/comment (#2831)
Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
2025-04-30 09:41:39 -07:00
Tomoya Fujita
c89a2b1013 subordinate node consistent behavior and update docstring. (#2822)
* subordinate node consistent behavior and update docstring.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* add subnode_parameter_operation test.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* typo fixes.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

---------

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2025-04-29 13:41:52 -07:00
Scott K Logan
1a282064a9 29.6.0 2025-04-25 15:04:18 -05:00
24 changed files with 591 additions and 386 deletions

View File

@@ -2,6 +2,12 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29.6.0 (2025-04-25)
-------------------
* throws std::invalid_argument if ParameterEvent is NULL. (`#2814 <https://github.com/ros2/rclcpp/issues/2814>`_)
* Removed clang warnings (`#2823 <https://github.com/ros2/rclcpp/issues/2823>`_)
* Contributors: Alejandro Hernández Cordero, Tomoya Fujita
29.5.0 (2025-04-18)
-------------------
* Fix a race condition (`#2819 <https://github.com/ros2/rclcpp/issues/2819>`_)

View File

@@ -200,21 +200,6 @@ public:
bool
ros_time_is_active();
/**
* Deprecated. This API is broken, as there is no way to get a deep
* copy of a clock. Therefore one can experience spurious wakeups triggered
* by some other instance of a clock.
*
* Cancels an ongoing or future sleep operation of one thread.
*
* This function can be used by one thread, to wakeup another thread that is
* blocked using any of the sleep_ or wait_ methods of this class.
*/
[[deprecated("Use ClockConditionalVariable")]]
RCLCPP_PUBLIC
void
cancel_sleep_or_wait();
/// Return the rcl_clock_t clock handle
RCLCPP_PUBLIC
rcl_clock_t *

View File

@@ -17,6 +17,7 @@
#include <memory>
#include <mutex>
#include <shared_mutex>
#include <stdexcept>
#include <utility>
#include <vector>
@@ -69,7 +70,7 @@ public:
*/
void enqueue(BufferT request) override
{
std::lock_guard<std::mutex> lock(mutex_);
std::unique_lock lock(mutex_);
write_index_ = next_(write_index_);
ring_buffer_[write_index_] = std::move(request);
@@ -95,7 +96,7 @@ public:
*/
BufferT dequeue() override
{
std::lock_guard<std::mutex> lock(mutex_);
std::unique_lock lock(mutex_);
if (!has_data_()) {
return BufferT();
@@ -134,7 +135,7 @@ public:
*/
inline size_t next(size_t val)
{
std::lock_guard<std::mutex> lock(mutex_);
std::unique_lock lock(mutex_);
return next_(val);
}
@@ -146,7 +147,7 @@ public:
*/
inline bool has_data() const override
{
std::lock_guard<std::mutex> lock(mutex_);
std::shared_lock lock(mutex_);
return has_data_();
}
@@ -159,7 +160,7 @@ public:
*/
inline bool is_full() const
{
std::lock_guard<std::mutex> lock(mutex_);
std::shared_lock lock(mutex_);
return is_full_();
}
@@ -171,13 +172,15 @@ public:
*/
size_t available_capacity() const override
{
std::lock_guard<std::mutex> lock(mutex_);
std::shared_lock lock(mutex_);
return available_capacity_();
}
void clear() override
{
TRACETOOLS_TRACEPOINT(rclcpp_ring_buffer_clear, static_cast<const void *>(this));
std::unique_lock lock(mutex_);
clear_();
}
private:
@@ -227,6 +230,14 @@ private:
return capacity_ - size_;
}
inline void clear_()
{
ring_buffer_.clear();
size_ = 0;
read_index_ = 0;
write_index_ = capacity_ - 1;
}
/// Traits for checking if a type is std::unique_ptr
template<typename ...>
struct is_std_unique_ptr final : std::false_type {};
@@ -251,7 +262,7 @@ private:
void> * = nullptr>
std::vector<BufferT> get_all_data_impl()
{
std::lock_guard<std::mutex> lock(mutex_);
std::unique_lock lock(mutex_);
std::vector<BufferT> result_vtr;
result_vtr.reserve(size_);
for (size_t id = 0; id < size_; ++id) {
@@ -266,7 +277,7 @@ private:
std::is_copy_constructible<T>::value, void> * = nullptr>
std::vector<BufferT> get_all_data_impl()
{
std::lock_guard<std::mutex> lock(mutex_);
std::unique_lock lock(mutex_);
std::vector<BufferT> result_vtr;
result_vtr.reserve(size_);
for (size_t id = 0; id < size_; ++id) {
@@ -292,7 +303,7 @@ private:
return {};
}
size_t capacity_;
const size_t capacity_;
std::vector<BufferT> ring_buffer_;
@@ -300,7 +311,7 @@ private:
size_t read_index_;
size_t size_;
mutable std::mutex mutex_;
mutable std::shared_mutex mutex_;
};
} // namespace buffers

View File

@@ -78,34 +78,6 @@ RCLCPP_PUBLIC
Logger
get_node_logger(const rcl_node_t * node);
// TODO(ahcorde): Remove deprecated class on the next release (in Rolling after Kilted).
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
/// Get the current logging directory.
/**
* For more details of how the logging directory is determined,
* see rcl_logging_get_logging_directory().
*
* \returns the logging directory being used.
* \throws rclcpp::exceptions::RCLError if an unexpected error occurs.
*/
[[deprecated("use rclcpp::get_log_directory instead of rclcpp::get_logging_directory")]]
RCLCPP_PUBLIC
rcpputils::fs::path
get_logging_directory();
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
/// Get the current logging directory.
/**
* For more details of how the logging directory is determined,

View File

@@ -1559,6 +1559,10 @@ public:
* which has been created using an existing instance of this class, but which
* has an additional sub-namespace (short for subordinate namespace)
* associated with it.
* A subordinate node and an instance of this class share all the node interfaces
* such as `rclcpp::node_interfaces::NodeParametersInterface`.
* Subordinate nodes are primarily used to organize namespaces and provide a
* hierarchical structure, but they are not meant to be completely independent nodes.
* The sub-namespace will extend the node's namespace for the purpose of
* creating additional entities, such as Publishers, Subscriptions, Service
* Clients and Servers, and so on.

View File

@@ -323,11 +323,9 @@ template<typename ParameterT>
bool
Node::get_parameter(const std::string & name, ParameterT & parameter) const
{
std::string sub_name = extend_name_with_sub_namespace(name, this->get_sub_namespace());
rclcpp::Parameter parameter_variant;
bool result = get_parameter(sub_name, parameter_variant);
bool result = get_parameter(name, parameter_variant);
if (result) {
parameter = static_cast<ParameterT>(parameter_variant.get_value<ParameterT>());
}
@@ -342,9 +340,7 @@ Node::get_parameter_or(
ParameterT & parameter,
const ParameterT & alternative_value) const
{
std::string sub_name = extend_name_with_sub_namespace(name, this->get_sub_namespace());
bool got_parameter = get_parameter(sub_name, parameter);
bool got_parameter = get_parameter(name, parameter);
if (!got_parameter) {
parameter = alternative_value;
}

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp</name>
<version>29.5.0</version>
<version>29.6.0</version>
<description>The ROS client library in C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -83,16 +83,6 @@ Clock::now() const
return now;
}
void
Clock::cancel_sleep_or_wait()
{
{
std::unique_lock lock(impl_->wait_mutex_);
impl_->stop_sleeping_ = true;
}
impl_->cv_.notify_one();
}
bool
Clock::sleep_until(
Time until,

View File

@@ -55,34 +55,6 @@ get_node_logger(const rcl_node_t * node)
return rclcpp::get_logger(logger_name);
}
// TODO(ahcorde): Remove deprecated class on the next release (in Rolling after Kilted).
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
rcpputils::fs::path
get_logging_directory()
{
char * log_dir = NULL;
auto allocator = rcutils_get_default_allocator();
rcl_logging_ret_t ret = rcl_logging_get_logging_directory(allocator, &log_dir);
if (RCL_LOGGING_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
std::string path{log_dir};
allocator.deallocate(log_dir, allocator.state);
return path;
}
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
std::filesystem::path
get_log_directory()
{

View File

@@ -689,7 +689,7 @@ Node::create_generic_client(
node_base_,
node_graph_,
node_services_,
service_name,
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
service_type,
qos,
group);

View File

@@ -192,6 +192,65 @@ format_range_reason(const std::string & name, const char * range_type)
return ss.str();
}
RCLCPP_LOCAL
rcl_interfaces::msg::SetParametersResult
__check_integer_range(
const rcl_interfaces::msg::ParameterDescriptor & descriptor,
const int64_t value)
{
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
auto integer_range = descriptor.integer_range.at(0);
if (value == integer_range.from_value || value == integer_range.to_value) {
return result;
}
if ((value < integer_range.from_value) || (value > integer_range.to_value)) {
result.successful = false;
result.reason = format_range_reason(descriptor.name, "integer");
return result;
}
if (integer_range.step == 0) {
return result;
}
if (((value - integer_range.from_value) % integer_range.step) == 0) {
return result;
}
result.successful = false;
result.reason = format_range_reason(descriptor.name, "integer");
return result;
}
RCLCPP_LOCAL
rcl_interfaces::msg::SetParametersResult
__check_double_range(
const rcl_interfaces::msg::ParameterDescriptor & descriptor,
const double value)
{
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
auto fp_range = descriptor.floating_point_range.at(0);
if (__are_doubles_equal(value, fp_range.from_value) || __are_doubles_equal(value,
fp_range.to_value))
{
return result;
}
if ((value < fp_range.from_value) || (value > fp_range.to_value)) {
result.successful = false;
result.reason = format_range_reason(descriptor.name, "floating point");
return result;
}
if (fp_range.step == 0.0) {
return result;
}
double rounded_div = std::round((value - fp_range.from_value) / fp_range.step);
if (__are_doubles_equal(value, fp_range.from_value + rounded_div * fp_range.step)) {
return result;
}
result.successful = false;
result.reason = format_range_reason(descriptor.name, "floating point");
return result;
}
RCLCPP_LOCAL
rcl_interfaces::msg::SetParametersResult
__check_parameter_value_in_range(
@@ -201,49 +260,39 @@ __check_parameter_value_in_range(
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
if (!descriptor.integer_range.empty() && value.get_type() == rclcpp::PARAMETER_INTEGER) {
int64_t v = value.get<int64_t>();
auto integer_range = descriptor.integer_range.at(0);
if (v == integer_range.from_value || v == integer_range.to_value) {
return result;
result = __check_integer_range(descriptor, value.get<int64_t>());
return result;
}
if (!descriptor.integer_range.empty() && value.get_type() == rclcpp::PARAMETER_INTEGER_ARRAY) {
std::vector<int64_t> val_array = value.get<std::vector<int64_t>>();
for (const int64_t & val : val_array) {
result = __check_integer_range(descriptor, val);
if (!result.successful) {
return result;
}
}
if ((v < integer_range.from_value) || (v > integer_range.to_value)) {
result.successful = false;
result.reason = format_range_reason(descriptor.name, "integer");
return result;
}
if (integer_range.step == 0) {
return result;
}
if (((v - integer_range.from_value) % integer_range.step) == 0) {
return result;
}
result.successful = false;
result.reason = format_range_reason(descriptor.name, "integer");
return result;
}
if (!descriptor.floating_point_range.empty() && value.get_type() == rclcpp::PARAMETER_DOUBLE) {
double v = value.get<double>();
auto fp_range = descriptor.floating_point_range.at(0);
if (__are_doubles_equal(v, fp_range.from_value) || __are_doubles_equal(v, fp_range.to_value)) {
return result;
}
if ((v < fp_range.from_value) || (v > fp_range.to_value)) {
result.successful = false;
result.reason = format_range_reason(descriptor.name, "floating point");
return result;
}
if (fp_range.step == 0.0) {
return result;
}
double rounded_div = std::round((v - fp_range.from_value) / fp_range.step);
if (__are_doubles_equal(v, fp_range.from_value + rounded_div * fp_range.step)) {
return result;
}
result.successful = false;
result.reason = format_range_reason(descriptor.name, "floating point");
result = __check_double_range(descriptor, value.get<double>());
return result;
}
if (!descriptor.floating_point_range.empty() &&
value.get_type() == rclcpp::PARAMETER_DOUBLE_ARRAY)
{
std::vector<double> val_array = value.get<std::vector<double>>();
for (const double & val : val_array) {
result = __check_double_range(descriptor, val);
if (!result.successful) {
return result;
}
}
return result;
}
return result;
}

View File

@@ -57,11 +57,6 @@ ament_add_test_label(test_client mimick)
if(TARGET test_client)
target_link_libraries(test_client ${PROJECT_NAME} mimick ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_clock test_clock.cpp)
ament_add_test_label(test_clock mimick)
if(TARGET test_clock)
target_link_libraries(test_clock ${PROJECT_NAME} mimick ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_clock_conditional test_clock_conditional.cpp)
ament_add_test_label(test_clock_conditional mimick)
if(TARGET test_clock_conditional)

View File

@@ -1,238 +0,0 @@
// Copyright 2024 Cellumation GmbH
//
// 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 <chrono>
#include <rcpputils/compile_warnings.hpp>
#include "rcl/error_handling.h"
#include "rcl/time.h"
#include "rclcpp/clock.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/time_source.hpp"
#include "../utils/rclcpp_gtest_macros.hpp"
using namespace std::chrono_literals;
class TestClockWakeup : public ::testing::TestWithParam<rcl_clock_type_e>
{
public:
void test_wakeup_before_sleep(const rclcpp::Clock::SharedPtr & clock)
{
std::atomic_bool thread_finished = false;
std::thread wait_thread = std::thread(
[&clock, &thread_finished]()
{
// make sure the thread starts sleeping late
std::this_thread::sleep_for(std::chrono::milliseconds(100));
clock->sleep_until(clock->now() + std::chrono::seconds(3));
thread_finished = true;
});
RCPPUTILS_DEPRECATION_WARNING_OFF_START
// notify the clock, that the sleep shall be interrupted
clock->cancel_sleep_or_wait();
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
while (!thread_finished && start_time + std::chrono::seconds(1) > cur_time) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
cur_time = std::chrono::steady_clock::now();
}
wait_thread.join();
EXPECT_TRUE(thread_finished);
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
}
void test_wakeup_after_sleep(const rclcpp::Clock::SharedPtr & clock)
{
std::atomic_bool thread_finished = false;
std::thread wait_thread = std::thread(
[&clock, &thread_finished]()
{
clock->sleep_until(clock->now() + std::chrono::seconds(3));
thread_finished = true;
});
// make sure the thread is already sleeping before we send the cancel
std::this_thread::sleep_for(std::chrono::milliseconds(100));
RCPPUTILS_DEPRECATION_WARNING_OFF_START
// notify the clock, that the sleep shall be interrupted
clock->cancel_sleep_or_wait();
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
while (!thread_finished && start_time + std::chrono::seconds(1) > cur_time) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
cur_time = std::chrono::steady_clock::now();
}
wait_thread.join();
EXPECT_TRUE(thread_finished);
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
}
protected:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
void SetUp()
{
node = std::make_shared<rclcpp::Node>("my_node");
}
void TearDown()
{
node.reset();
}
rclcpp::Node::SharedPtr node;
};
INSTANTIATE_TEST_SUITE_P(
Clocks,
TestClockWakeup,
::testing::Values(
RCL_SYSTEM_TIME, RCL_ROS_TIME, RCL_STEADY_TIME
));
TEST_P(TestClockWakeup, wakeup_sleep) {
auto clock = std::make_shared<rclcpp::Clock>(GetParam());
test_wakeup_after_sleep(clock);
test_wakeup_before_sleep(clock);
}
TEST_F(TestClockWakeup, wakeup_sleep_ros_time_active) {
node->set_parameter({"use_sim_time", true});
auto clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
rclcpp::TimeSource time_source(node);
time_source.attachClock(clock);
EXPECT_TRUE(clock->ros_time_is_active());
test_wakeup_after_sleep(clock);
test_wakeup_before_sleep(clock);
}
TEST_F(TestClockWakeup, no_wakeup_on_sim_time) {
node->set_parameter({"use_sim_time", true});
auto clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
rclcpp::TimeSource time_source(node);
time_source.attachClock(clock);
EXPECT_TRUE(clock->ros_time_is_active());
std::atomic_bool thread_finished = false;
std::thread wait_thread = std::thread(
[&clock, &thread_finished]()
{
// make sure the thread starts sleeping late
clock->sleep_until(clock->now() + std::chrono::milliseconds(10));
thread_finished = true;
});
// make sure, that the sim time clock does not wakeup, as no clock is provided
std::this_thread::sleep_for(std::chrono::milliseconds(500));
EXPECT_FALSE(thread_finished);
RCPPUTILS_DEPRECATION_WARNING_OFF_START
// notify the clock, that the sleep shall be interrupted
clock->cancel_sleep_or_wait();
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
while (!thread_finished && start_time + std::chrono::seconds(1) > cur_time) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
cur_time = std::chrono::steady_clock::now();
}
wait_thread.join();
EXPECT_TRUE(thread_finished);
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
}
TEST_F(TestClockWakeup, multiple_threads_wait_on_one_clock) {
auto clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
std::vector<std::atomic_bool> thread_finished(10);
for (std::atomic_bool & finished : thread_finished) {
finished = false;
}
std::vector<std::thread> threads;
for (size_t nr = 0; nr < thread_finished.size(); nr++) {
threads.push_back(
std::thread(
[&clock, &thread_finished, nr]()
{
// make sure the thread starts sleeping late
clock->sleep_until(clock->now() + std::chrono::seconds(10));
thread_finished[nr] = true;
}));
}
// wait a bit so all threads can execute the sleep_until
std::this_thread::sleep_for(std::chrono::milliseconds(500));
for (const std::atomic_bool & finished : thread_finished) {
EXPECT_FALSE(finished);
}
rclcpp::shutdown();
auto start_time = std::chrono::steady_clock::now();
auto cur_time = start_time;
bool threads_finished = false;
while (!threads_finished && start_time + std::chrono::seconds(1) > cur_time) {
threads_finished = true;
for (const std::atomic_bool & finished : thread_finished) {
if (!finished) {
threads_finished = false;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
cur_time = std::chrono::steady_clock::now();
}
for (const std::atomic_bool & finished : thread_finished) {
EXPECT_TRUE(finished);
}
for (auto & thread : threads) {
thread.join();
}
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
}

View File

@@ -221,7 +221,7 @@ TEST_F(TestGenericClient, wait_for_service) {
TEST_F(TestGenericClientSub, construction_and_destruction) {
{
auto client = subnode->create_generic_client("test_service", "test_msgs/srv/Empty");
EXPECT_STREQ(client->get_service_name(), "/ns/test_service");
EXPECT_STREQ(client->get_service_name(), "/ns/sub_ns/test_service");
}
{

View File

@@ -21,7 +21,7 @@
#include "rclcpp/rclcpp.hpp"
/*
Construtctor
Constructor
*/
TEST(TestIntraProcessBuffer, constructor) {
using MessageT = char;

View File

@@ -306,6 +306,39 @@ TEST_F(TestNode, subnode_get_name_and_namespace) {
}, rclcpp::exceptions::NameValidationError);
}
}
TEST_F(TestNode, subnode_parameter_operation) {
auto node = std::make_shared<rclcpp::Node>("my_node", "ns");
auto subnode = node->create_sub_node("sub_ns");
auto value = subnode->declare_parameter("param", 5);
EXPECT_EQ(value, 5);
// node and sub-node shares NodeParametersInterface, so expecting the exception.
EXPECT_THROW(
node->declare_parameter("param", 0),
rclcpp::exceptions::ParameterAlreadyDeclaredException);
rclcpp::Parameter param;
node->get_parameter("param", param);
EXPECT_EQ(param.get_value<int>(), 5);
subnode->get_parameter("param", param);
EXPECT_EQ(param.get_value<int>(), 5);
int param_int;
node->get_parameter("param", param_int);
EXPECT_EQ(param_int, 5);
subnode->get_parameter("param", param_int);
EXPECT_EQ(param_int, 5);
EXPECT_EQ(node->get_parameter_or("param", 333), 5);
EXPECT_EQ(subnode->get_parameter_or("param", 666), 5);
node->get_parameter_or("param", param_int, 333);
EXPECT_EQ(param_int, 5);
subnode->get_parameter_or("param", param_int, 666);
EXPECT_EQ(param_int, 5);
}
/*
Testing node construction and destruction.
*/
@@ -1332,6 +1365,203 @@ TEST_F(TestNode, set_parameter_undeclared_parameters_not_allowed) {
node->declare_parameter(name, 42, descriptor),
rclcpp::exceptions::InvalidParameterValueException);
}
{
// setting an array parameter with integer range descriptor
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.integer_range.resize(1);
auto & integer_range = descriptor.integer_range.at(0);
integer_range.from_value = 10;
integer_range.to_value = 18;
integer_range.step = 2;
node->declare_parameter(name, std::vector<int64_t>{10, 12, 14, 16, 18}, descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
EXPECT_EQ(value.get_value<std::vector<int64_t>>(), std::vector<int64_t>({10, 12, 14, 16, 18}));
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({12, 14, 10}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({12, 14, 10}));
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({10, 10, 10}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({10, 10, 10}));
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({18}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({15}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({20}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({8}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({12, 8, 18}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18}));
}
{
// setting an array parameter with integer range descriptor, from_value > to_value
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.integer_range.resize(1);
auto & integer_range = descriptor.integer_range.at(0);
integer_range.from_value = 20;
integer_range.to_value = 18;
integer_range.step = 1;
node->declare_parameter(name, std::vector<int64_t>({18, 20}), descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
EXPECT_EQ(value.get_value<std::vector<int64_t>>(), std::vector<int64_t>({18, 20}));
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({20, 18}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({20, 18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({18, 19, 20}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({20, 18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({10}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({20, 18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({25}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({20, 18}));
}
{
// setting an array parameter with integer range descriptor, from_value = to_value
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.integer_range.resize(1);
auto & integer_range = descriptor.integer_range.at(0);
integer_range.from_value = 18;
integer_range.to_value = 18;
integer_range.step = 1;
node->declare_parameter(name, std::vector<int64_t>({18}), descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
EXPECT_EQ(value.get_value<std::vector<int64_t>>(), std::vector<int64_t>({18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({17}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({19}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18}));
}
{
// setting an array parameter with integer range descriptor,
// step > distance(from_value, to_value)
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.integer_range.resize(1);
auto & integer_range = descriptor.integer_range.at(0);
integer_range.from_value = 18;
integer_range.to_value = 25;
integer_range.step = 10;
node->declare_parameter(name, std::vector<int64_t>({18, 25}), descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
EXPECT_EQ(value.get_value<std::vector<int64_t>>(), std::vector<int64_t>({18, 25}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({17}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18, 25}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({19}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18, 25}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({28}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18, 25}));
}
{
// setting an array parameter with integer range descriptor, distance not multiple of the step.
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.integer_range.resize(1);
auto & integer_range = descriptor.integer_range.at(0);
integer_range.from_value = 18;
integer_range.to_value = 28;
integer_range.step = 7;
node->declare_parameter(name, std::vector<int64_t>({18, 25, 28}), descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
EXPECT_EQ(value.get_value<std::vector<int64_t>>(), std::vector<int64_t>({18, 25, 28}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({17}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18, 25, 28}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({19}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18, 25, 28}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({32}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({18, 25, 28}));
}
{
// setting an array parameter with integer range descriptor, step=0
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.integer_range.resize(1);
auto & integer_range = descriptor.integer_range.at(0);
integer_range.from_value = 10;
integer_range.to_value = 18;
integer_range.step = 0;
node->declare_parameter(name, std::vector<int64_t>({10, 11, 12, 13, 14, 15, 16, 17, 18}),
descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
EXPECT_EQ(value.get_value<std::vector<int64_t>>(),
std::vector<int64_t>({10, 11, 12, 13, 14, 15, 16, 17, 18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({9}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({10, 11, 12, 13, 14, 15, 16, 17, 18}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<int64_t>({19}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
std::vector<int64_t>({10, 11, 12, 13, 14, 15, 16, 17, 18}));
}
{
// setting an array parameter with integer range descriptor and wrong default value will throw
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.integer_range.resize(1);
auto & integer_range = descriptor.integer_range.at(0);
integer_range.from_value = 10;
integer_range.to_value = 18;
integer_range.step = 2;
ASSERT_THROW(
node->declare_parameter(name, std::vector<int64_t>({10, 11, 12, 13, 14, 15, 16, 17, 18}),
descriptor),
rclcpp::exceptions::InvalidParameterValueException);
}
{
// setting a parameter with floating point range descriptor
auto name = "parameter"_unq;
@@ -1502,6 +1732,201 @@ TEST_F(TestNode, set_parameter_undeclared_parameters_not_allowed) {
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 9.999)).successful);
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
}
{
// setting an array parameter with floating point range descriptor
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.floating_point_range.resize(1);
auto & floating_point_range = descriptor.floating_point_range.at(0);
floating_point_range.from_value = 10.0;
floating_point_range.to_value = 11.0;
floating_point_range.step = 0.2;
node->declare_parameter(name, std::vector<double>({10.0, 10.4, 11.0, 10.8, 10.2, 10.6}),
descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
EXPECT_EQ(value.get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.4, 11.0, 10.8, 10.2, 10.6}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({10.3}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.4, 11.0, 10.8, 10.2, 10.6}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({12.0}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.4, 11.0, 10.8, 10.2, 10.6}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({9.4}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.4, 11.0, 10.8, 10.2, 10.6}));
}
{
// setting an array parameter with floating point range descriptor, negative step
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.floating_point_range.resize(1);
auto & floating_point_range = descriptor.floating_point_range.at(0);
floating_point_range.from_value = 10.0;
floating_point_range.to_value = 11.0;
floating_point_range.step = -0.2;
node->declare_parameter(name, std::vector<double>({10.0, 10.2, 10.4, 10.6, 10.8, 11.0}),
descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
EXPECT_EQ(value.get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.2, 10.4, 10.6, 10.8, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({10.3}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.2, 10.4, 10.6, 10.8, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({12.0}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.2, 10.4, 10.6, 10.8, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({9.4}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.2, 10.4, 10.6, 10.8, 11.0}));
}
{
// setting an array parameter with floating point range descriptor, from_value > to_value
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.floating_point_range.resize(1);
auto & floating_point_range = descriptor.floating_point_range.at(0);
floating_point_range.from_value = 11.0;
floating_point_range.to_value = 10.0;
floating_point_range.step = 0.2;
node->declare_parameter(name, std::vector<double>({10.0, 11.0}), descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
EXPECT_EQ(value.get_value<std::vector<double>>(), std::vector<double>({10.0, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({10.2}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({12.0}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({9.4}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 11.0}));
}
{
// setting an array parameter with floating point range descriptor, from_value = to_value
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.floating_point_range.resize(1);
auto & floating_point_range = descriptor.floating_point_range.at(0);
floating_point_range.from_value = 10.0;
floating_point_range.to_value = 10.0;
floating_point_range.step = 0.2;
node->declare_parameter(name, std::vector<double>({10.0}), descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
EXPECT_EQ(value.get_value<std::vector<double>>(), std::vector<double>({10.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({11.2}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({12.0}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({9.4}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0}));
}
{
// setting an array parameter with floating point range descriptor, step > distance
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.floating_point_range.resize(1);
auto & floating_point_range = descriptor.floating_point_range.at(0);
floating_point_range.from_value = 10.0;
floating_point_range.to_value = 11.0;
floating_point_range.step = 2.2;
node->declare_parameter(name, std::vector<double>({10.0, 11.0}), descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
EXPECT_EQ(value.get_value<std::vector<double>>(), std::vector<double>({10.0, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({12.2}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({7.8}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 11.0}));
}
{
// setting an array parameter with floating point range descriptor,
// distance not multiple of the step.
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.floating_point_range.resize(1);
auto & floating_point_range = descriptor.floating_point_range.at(0);
floating_point_range.from_value = 10.0;
floating_point_range.to_value = 11.0;
floating_point_range.step = 0.7;
node->declare_parameter(name, std::vector<double>({10.0, 10.7, 11.0}), descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
EXPECT_EQ(value.get_value<std::vector<double>>(), std::vector<double>({10.0, 10.7, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({12.2}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.7, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({11.4}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.7, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({9.3}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.7, 11.0}));
}
{
// setting an array parameter with floating point range descriptor, step=0
auto name = "parameter"_unq;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.floating_point_range.resize(1);
auto & floating_point_range = descriptor.floating_point_range.at(0);
floating_point_range.from_value = 10.0;
floating_point_range.to_value = 11.0;
floating_point_range.step = 0.0;
node->declare_parameter(name, std::vector<double>({10.0, 10.0001, 10.5479051, 11.0}),
descriptor);
EXPECT_TRUE(node->has_parameter(name));
auto value = node->get_parameter(name);
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
EXPECT_EQ(value.get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.0001, 10.5479051, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({11.001}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.0001, 10.5479051, 11.0}));
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
std::vector<double>({9.999}))).successful);
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
std::vector<double>({10.0, 10.0001, 10.5479051, 11.0}));
}
{
// setting a parameter with a different type is still possible
// when having a descriptor specifying a type (type is a status, not a constraint).

View File

@@ -22,7 +22,7 @@
#include "rclcpp/experimental/buffers/ring_buffer_implementation.hpp"
/*
* Construtctor
* Constructor
*/
TEST(TestRingBufferImplementation, constructor) {
// Cannot create a buffer of size zero.
@@ -139,3 +139,28 @@ TEST(TestRingBufferImplementation, basic_usage_unique_ptr) {
EXPECT_EQ(false, rb.has_data());
EXPECT_EQ(false, rb.is_full());
}
TEST(TestRingBufferImplementation, test_buffer_clear) {
rclcpp::experimental::buffers::RingBufferImplementation<char> rb(2);
rb.enqueue('a');
rb.enqueue('b');
EXPECT_EQ(true, rb.has_data());
EXPECT_EQ(true, rb.is_full());
const auto all_data_vec = rb.get_all_data();
EXPECT_EQ(2u, all_data_vec.capacity());
EXPECT_EQ(2u, all_data_vec.size());
rb.clear();
EXPECT_EQ(false, rb.has_data());
EXPECT_EQ(false, rb.is_full());
const auto all_data_vec_empty = rb.get_all_data();
EXPECT_EQ(0u, all_data_vec_empty.capacity());
EXPECT_EQ(0u, all_data_vec_empty.size());
rb.enqueue('c');
rb.enqueue('d');
const auto c = rb.dequeue();
const auto d = rb.dequeue();
EXPECT_EQ('c', c);
EXPECT_EQ('d', d);
}

View File

@@ -3,6 +3,9 @@ Changelog for package rclcpp_action
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29.6.0 (2025-04-25)
-------------------
29.5.0 (2025-04-18)
-------------------
* Use std::recursive_mutex for action requests. (`#2798 <https://github.com/ros2/rclcpp/issues/2798>`_)

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp_action</name>
<version>29.5.0</version>
<version>29.6.0</version>
<description>Adds action APIs for C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -2,6 +2,9 @@
Changelog for package rclcpp_components
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29.6.0 (2025-04-25)
-------------------
29.5.0 (2025-04-18)
-------------------

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp_components</name>
<version>29.5.0</version>
<version>29.6.0</version>
<description>Package containing tools for dynamically loadable components</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -3,6 +3,9 @@ Changelog for package rclcpp_lifecycle
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
29.6.0 (2025-04-25)
-------------------
29.5.0 (2025-04-18)
-------------------

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp_lifecycle</name>
<version>29.5.0</version>
<version>29.6.0</version>
<description>Package containing a prototype for lifecycle implementation</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -409,10 +409,14 @@ LifecycleNode::LifecycleNodeInterfaceImpl::change_state(
rcl_lifecycle_trigger_transition_by_id(
&state_machine_, transition_id, publish_update) != RCL_RET_OK)
{
const char * transition_label = rcl_lifecycle_get_transition_label_by_id(
&state_machine_.transition_map, transition_id);
RCLCPP_ERROR(
node_logging_interface_->get_logger(),
"Unable to start transition %u from current state %s: %s",
transition_id, state_machine_.current_state->label, rcl_get_error_string().str);
"Unable to start transition %u (%s) from current state %s: %s",
transition_id,
transition_label ? transition_label : "unknown transition",
state_machine_.current_state->label, rcl_get_error_string().str);
rcutils_reset_error();
return RCL_RET_ERROR;
}