Compare commits
9 Commits
29.5.1
...
fujitatomo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
546f3ae655 | ||
|
|
4f507751e1 | ||
|
|
7bd14d812c | ||
|
|
e97d569f75 | ||
|
|
f81caaca49 | ||
|
|
127a10e8c8 | ||
|
|
b1ec85df16 | ||
|
|
c89a2b1013 | ||
|
|
1a282064a9 |
@@ -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>`_)
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
/*
|
||||
Construtctor
|
||||
Constructor
|
||||
*/
|
||||
TEST(TestIntraProcessBuffer, constructor) {
|
||||
using MessageT = char;
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>`_)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
Changelog for package rclcpp_components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
29.6.0 (2025-04-25)
|
||||
-------------------
|
||||
|
||||
29.5.0 (2025-04-18)
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -3,6 +3,9 @@ Changelog for package rclcpp_lifecycle
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
29.6.0 (2025-04-25)
|
||||
-------------------
|
||||
|
||||
29.5.0 (2025-04-18)
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user