Compare commits
5 Commits
runtime_in
...
16.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae8b033ae0 | ||
|
|
4fa3489cfd | ||
|
|
7f575103d8 | ||
|
|
166007dde3 | ||
|
|
cf2a27805e |
@@ -2,6 +2,14 @@
|
||||
Changelog for package rclcpp
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
16.0.2 (2022-11-07)
|
||||
-------------------
|
||||
* fix mismatched issue if using zero_allocate (`#1995 <https://github.com/ros2/rclcpp/issues/1995>`_) (`#2026 <https://github.com/ros2/rclcpp/issues/2026>`_)
|
||||
* use regex for wildcard matching (backport `#1839 <https://github.com/ros2/rclcpp/issues/1839>`_) (`#1986 <https://github.com/ros2/rclcpp/issues/1986>`_)
|
||||
* Drop wrong template specialization (`#1926 <https://github.com/ros2/rclcpp/issues/1926>`_) (`#1937 <https://github.com/ros2/rclcpp/issues/1937>`_)
|
||||
* Add statistics for handle_loaned_message (`#1927 <https://github.com/ros2/rclcpp/issues/1927>`_) (`#1932 <https://github.com/ros2/rclcpp/issues/1932>`_)
|
||||
* Contributors: mergify[bot]
|
||||
|
||||
16.0.1 (2022-04-13)
|
||||
-------------------
|
||||
* remove DEFINE_CONTENT_FILTER cmake option (`#1914 <https://github.com/ros2/rclcpp/issues/1914>`_)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef RCLCPP__ALLOCATOR__ALLOCATOR_COMMON_HPP_
|
||||
#define RCLCPP__ALLOCATOR__ALLOCATOR_COMMON_HPP_
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include "rcl/allocator.h"
|
||||
@@ -39,6 +40,22 @@ void * retyped_allocate(size_t size, void * untyped_allocator)
|
||||
return std::allocator_traits<Alloc>::allocate(*typed_allocator, size);
|
||||
}
|
||||
|
||||
template<typename Alloc>
|
||||
void * retyped_zero_allocate(size_t number_of_elem, size_t size_of_elem, void * untyped_allocator)
|
||||
{
|
||||
auto typed_allocator = static_cast<Alloc *>(untyped_allocator);
|
||||
if (!typed_allocator) {
|
||||
throw std::runtime_error("Received incorrect allocator type");
|
||||
}
|
||||
size_t size = number_of_elem * size_of_elem;
|
||||
void * allocated_memory =
|
||||
std::allocator_traits<Alloc>::allocate(*typed_allocator, size);
|
||||
if (allocated_memory) {
|
||||
std::memset(allocated_memory, 0, size);
|
||||
}
|
||||
return allocated_memory;
|
||||
}
|
||||
|
||||
template<typename T, typename Alloc>
|
||||
void retyped_deallocate(void * untyped_pointer, void * untyped_allocator)
|
||||
{
|
||||
@@ -73,6 +90,7 @@ rcl_allocator_t get_rcl_allocator(Alloc & allocator)
|
||||
rcl_allocator_t rcl_allocator = rcl_get_default_allocator();
|
||||
#ifndef _WIN32
|
||||
rcl_allocator.allocate = &retyped_allocate<Alloc>;
|
||||
rcl_allocator.zero_allocate = &retyped_zero_allocate<Alloc>;
|
||||
rcl_allocator.deallocate = &retyped_deallocate<T, Alloc>;
|
||||
rcl_allocator.reallocate = &retyped_reallocate<T, Alloc>;
|
||||
rcl_allocator.state = &allocator;
|
||||
|
||||
@@ -41,6 +41,16 @@ RCLCPP_PUBLIC
|
||||
ParameterMap
|
||||
parameter_map_from(const rcl_params_t * const c_params);
|
||||
|
||||
/// Convert parameters from rcl_yaml_param_parser into C++ class instances.
|
||||
/// \param[in] c_params C structures containing parameters for multiple nodes.
|
||||
/// \param[in] node_fqn a Fully Qualified Name of node, default value is nullptr.
|
||||
/// If it's not nullptr, return the relative node parameters belonging to this node_fqn.
|
||||
/// \returns a map where the keys are fully qualified node names and values a list of parameters.
|
||||
/// \throws InvalidParametersException if the `rcl_params_t` is inconsistent or invalid.
|
||||
RCLCPP_PUBLIC
|
||||
ParameterMap
|
||||
parameter_map_from(const rcl_params_t * const c_params, const char * node_fqn);
|
||||
|
||||
/// Convert parameter value from rcl_yaml_param_parser into a C++ class instance.
|
||||
/// \param[in] c_value C structure containing a value of a parameter.
|
||||
/// \returns an instance of a parameter value
|
||||
|
||||
@@ -72,7 +72,7 @@ struct PublisherOptionsWithAllocator : public PublisherOptionsBase
|
||||
/// Optional custom allocator.
|
||||
std::shared_ptr<Allocator> allocator = nullptr;
|
||||
|
||||
PublisherOptionsWithAllocator<Allocator>() {}
|
||||
PublisherOptionsWithAllocator() {}
|
||||
|
||||
/// Constructor using base class as input.
|
||||
explicit PublisherOptionsWithAllocator(const PublisherOptionsBase & publisher_options_base)
|
||||
|
||||
@@ -363,11 +363,31 @@ public:
|
||||
void * loaned_message,
|
||||
const rclcpp::MessageInfo & message_info) override
|
||||
{
|
||||
if (matches_any_intra_process_publishers(&message_info.get_rmw_message_info().publisher_gid)) {
|
||||
// In this case, the message will be delivered via intra process and
|
||||
// we should ignore this copy of the message.
|
||||
return;
|
||||
}
|
||||
|
||||
auto typed_message = static_cast<ROSMessageType *>(loaned_message);
|
||||
// message is loaned, so we have to make sure that the deleter does not deallocate the message
|
||||
auto sptr = std::shared_ptr<ROSMessageType>(
|
||||
typed_message, [](ROSMessageType * msg) {(void) msg;});
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> now;
|
||||
if (subscription_topic_statistics_) {
|
||||
// get current time before executing callback to
|
||||
// exclude callback duration from topic statistics result.
|
||||
now = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
any_callback_.dispatch(sptr, message_info);
|
||||
|
||||
if (subscription_topic_statistics_) {
|
||||
const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
|
||||
const auto time = rclcpp::Time(nanos.time_since_epoch().count());
|
||||
subscription_topic_statistics_->handle_message(*typed_message, time);
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the borrowed message.
|
||||
|
||||
@@ -97,7 +97,7 @@ struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
|
||||
/// Optional custom allocator.
|
||||
std::shared_ptr<Allocator> allocator = nullptr;
|
||||
|
||||
SubscriptionOptionsWithAllocator<Allocator>() {}
|
||||
SubscriptionOptionsWithAllocator() {}
|
||||
|
||||
/// Constructor using base class as input.
|
||||
explicit SubscriptionOptionsWithAllocator(
|
||||
|
||||
@@ -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>16.0.1</version>
|
||||
<version>16.0.2</version>
|
||||
<description>The ROS client library in C++.</description>
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
<maintainer email="jacob@openrobotics.org">Jacob Perron</maintainer>
|
||||
|
||||
@@ -51,18 +51,13 @@ rclcpp::detail::resolve_parameter_overrides(
|
||||
[params]() {
|
||||
rcl_yaml_node_struct_fini(params);
|
||||
});
|
||||
rclcpp::ParameterMap initial_map = rclcpp::parameter_map_from(params);
|
||||
rclcpp::ParameterMap initial_map = rclcpp::parameter_map_from(params, node_fqn.c_str());
|
||||
|
||||
// Enforce wildcard matching precedence
|
||||
// TODO(cottsay) implement further wildcard matching
|
||||
const std::array<std::string, 2> node_matching_names{"/**", node_fqn};
|
||||
for (const auto & node_name : node_matching_names) {
|
||||
if (initial_map.count(node_name) > 0) {
|
||||
// Combine parameter yaml files, overwriting values in older ones
|
||||
for (const rclcpp::Parameter & param : initial_map.at(node_name)) {
|
||||
result[param.get_name()] =
|
||||
rclcpp::ParameterValue(param.get_value_message());
|
||||
}
|
||||
if (initial_map.count(node_fqn) > 0) {
|
||||
// Combine parameter yaml files, overwriting values in older ones
|
||||
for (const rclcpp::Parameter & param : initial_map.at(node_fqn)) {
|
||||
result[param.get_name()] =
|
||||
rclcpp::ParameterValue(param.get_value_message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <vector>
|
||||
|
||||
#include "rcpputils/find_and_replace.hpp"
|
||||
#include "rclcpp/parameter_map.hpp"
|
||||
|
||||
using rclcpp::exceptions::InvalidParametersException;
|
||||
@@ -24,6 +26,12 @@ using rclcpp::ParameterValue;
|
||||
|
||||
ParameterMap
|
||||
rclcpp::parameter_map_from(const rcl_params_t * const c_params)
|
||||
{
|
||||
return parameter_map_from(c_params, nullptr);
|
||||
}
|
||||
|
||||
ParameterMap
|
||||
rclcpp::parameter_map_from(const rcl_params_t * const c_params, const char * node_fqn)
|
||||
{
|
||||
if (NULL == c_params) {
|
||||
throw InvalidParametersException("parameters struct is NULL");
|
||||
@@ -49,6 +57,17 @@ rclcpp::parameter_map_from(const rcl_params_t * const c_params)
|
||||
node_name = c_node_name;
|
||||
}
|
||||
|
||||
if (node_fqn) {
|
||||
// Update the regular expression ["/*" -> "(/\\w+)" and "/**" -> "(/\\w+)*"]
|
||||
std::string regex = rcpputils::find_and_replace(node_name, "/*", "(/\\w+)");
|
||||
if (!std::regex_match(node_fqn, std::regex(regex))) {
|
||||
// No need to parse the items because the user just care about node_fqn
|
||||
continue;
|
||||
}
|
||||
|
||||
node_name = node_fqn;
|
||||
}
|
||||
|
||||
const rcl_node_params_t * const c_params_node = &(c_params->params[n]);
|
||||
|
||||
std::vector<Parameter> & params_node = parameters[node_name];
|
||||
@@ -65,6 +84,7 @@ rclcpp::parameter_map_from(const rcl_params_t * const c_params)
|
||||
params_node.emplace_back(c_param_name, parameter_value_from(c_param_value));
|
||||
}
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,53 @@ TEST(TestAllocatorCommon, retyped_allocate) {
|
||||
EXPECT_NO_THROW(code2());
|
||||
}
|
||||
|
||||
TEST(TestAllocatorCommon, retyped_zero_allocate_basic) {
|
||||
std::allocator<int> allocator;
|
||||
void * untyped_allocator = &allocator;
|
||||
void * allocated_mem =
|
||||
rclcpp::allocator::retyped_zero_allocate<std::allocator<char>>(20u, 1u, untyped_allocator);
|
||||
ASSERT_TRUE(nullptr != allocated_mem);
|
||||
|
||||
auto code = [&untyped_allocator, allocated_mem]() {
|
||||
rclcpp::allocator::retyped_deallocate<char, std::allocator<char>>(
|
||||
allocated_mem, untyped_allocator);
|
||||
};
|
||||
EXPECT_NO_THROW(code());
|
||||
}
|
||||
|
||||
TEST(TestAllocatorCommon, retyped_zero_allocate) {
|
||||
std::allocator<int> allocator;
|
||||
void * untyped_allocator = &allocator;
|
||||
void * allocated_mem =
|
||||
rclcpp::allocator::retyped_zero_allocate<std::allocator<char>>(20u, 1u, untyped_allocator);
|
||||
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
|
||||
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
|
||||
ASSERT_TRUE(nullptr != allocated_mem);
|
||||
|
||||
auto code = [&untyped_allocator, allocated_mem]() {
|
||||
rclcpp::allocator::retyped_deallocate<int, std::allocator<int>>(
|
||||
allocated_mem, untyped_allocator);
|
||||
};
|
||||
EXPECT_NO_THROW(code());
|
||||
|
||||
allocated_mem = allocator.allocate(1);
|
||||
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
|
||||
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
|
||||
ASSERT_TRUE(nullptr != allocated_mem);
|
||||
void * reallocated_mem =
|
||||
rclcpp::allocator::retyped_reallocate<int, std::allocator<int>>(
|
||||
allocated_mem, 2u, untyped_allocator);
|
||||
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
|
||||
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
|
||||
ASSERT_TRUE(nullptr != reallocated_mem);
|
||||
|
||||
auto code2 = [&untyped_allocator, reallocated_mem]() {
|
||||
rclcpp::allocator::retyped_deallocate<int, std::allocator<int>>(
|
||||
reallocated_mem, untyped_allocator);
|
||||
};
|
||||
EXPECT_NO_THROW(code2());
|
||||
}
|
||||
|
||||
TEST(TestAllocatorCommon, get_rcl_allocator) {
|
||||
std::allocator<int> allocator;
|
||||
auto rcl_allocator = rclcpp::allocator::get_rcl_allocator<int>(allocator);
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include "../../mocking_utils/patch.hpp"
|
||||
#include "../../utils/rclcpp_gtest_macros.hpp"
|
||||
|
||||
#include "rcpputils/filesystem_helper.hpp"
|
||||
|
||||
class TestNodeParameters : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
@@ -47,6 +49,7 @@ public:
|
||||
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
|
||||
node->get_node_parameters_interface().get());
|
||||
ASSERT_NE(nullptr, node_parameters);
|
||||
test_resources_path /= "test_node_parameters";
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
@@ -57,6 +60,8 @@ public:
|
||||
protected:
|
||||
std::shared_ptr<rclcpp::Node> node;
|
||||
rclcpp::node_interfaces::NodeParameters * node_parameters;
|
||||
|
||||
rcpputils::fs::path test_resources_path{TEST_RESOURCES_DIRECTORY};
|
||||
};
|
||||
|
||||
TEST_F(TestNodeParameters, construct_destruct_rcl_errors) {
|
||||
@@ -199,3 +204,130 @@ TEST_F(TestNodeParameters, add_remove_parameters_callback) {
|
||||
node_parameters->remove_on_set_parameters_callback(handle.get()),
|
||||
std::runtime_error("Callback doesn't exist"));
|
||||
}
|
||||
|
||||
TEST_F(TestNodeParameters, wildcard_with_namespace)
|
||||
{
|
||||
rclcpp::NodeOptions opts;
|
||||
opts.arguments(
|
||||
{
|
||||
"--ros-args",
|
||||
"--params-file", (test_resources_path / "wildcards.yaml").string()
|
||||
});
|
||||
|
||||
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node2", "ns", opts);
|
||||
|
||||
auto * node_parameters =
|
||||
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
|
||||
node->get_node_parameters_interface().get());
|
||||
ASSERT_NE(nullptr, node_parameters);
|
||||
|
||||
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
|
||||
EXPECT_EQ(7u, parameter_overrides.size());
|
||||
EXPECT_EQ(parameter_overrides.at("full_wild").get<std::string>(), "full_wild");
|
||||
EXPECT_EQ(parameter_overrides.at("namespace_wild").get<std::string>(), "namespace_wild");
|
||||
EXPECT_EQ(
|
||||
parameter_overrides.at("namespace_wild_another").get<std::string>(),
|
||||
"namespace_wild_another");
|
||||
EXPECT_EQ(
|
||||
parameter_overrides.at("namespace_wild_one_star").get<std::string>(),
|
||||
"namespace_wild_one_star");
|
||||
EXPECT_EQ(parameter_overrides.at("node_wild_in_ns").get<std::string>(), "node_wild_in_ns");
|
||||
EXPECT_EQ(
|
||||
parameter_overrides.at("node_wild_in_ns_another").get<std::string>(),
|
||||
"node_wild_in_ns_another");
|
||||
EXPECT_EQ(parameter_overrides.at("explicit_in_ns").get<std::string>(), "explicit_in_ns");
|
||||
EXPECT_EQ(parameter_overrides.count("should_not_appear"), 0u);
|
||||
}
|
||||
|
||||
TEST_F(TestNodeParameters, wildcard_no_namespace)
|
||||
{
|
||||
rclcpp::NodeOptions opts;
|
||||
opts.arguments(
|
||||
{
|
||||
"--ros-args",
|
||||
"--params-file", (test_resources_path / "wildcards.yaml").string()
|
||||
});
|
||||
|
||||
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node2", opts);
|
||||
|
||||
auto * node_parameters =
|
||||
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
|
||||
node->get_node_parameters_interface().get());
|
||||
ASSERT_NE(nullptr, node_parameters);
|
||||
|
||||
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
|
||||
EXPECT_EQ(5u, parameter_overrides.size());
|
||||
EXPECT_EQ(parameter_overrides.at("full_wild").get<std::string>(), "full_wild");
|
||||
EXPECT_EQ(parameter_overrides.at("namespace_wild").get<std::string>(), "namespace_wild");
|
||||
EXPECT_EQ(
|
||||
parameter_overrides.at("namespace_wild_another").get<std::string>(),
|
||||
"namespace_wild_another");
|
||||
EXPECT_EQ(parameter_overrides.at("node_wild_no_ns").get<std::string>(), "node_wild_no_ns");
|
||||
EXPECT_EQ(parameter_overrides.at("explicit_no_ns").get<std::string>(), "explicit_no_ns");
|
||||
EXPECT_EQ(parameter_overrides.count("should_not_appear"), 0u);
|
||||
// "/*" match exactly one token, not expect to get `namespace_wild_one_star`
|
||||
EXPECT_EQ(parameter_overrides.count("namespace_wild_one_star"), 0u);
|
||||
}
|
||||
|
||||
TEST_F(TestNodeParameters, params_by_order)
|
||||
{
|
||||
rclcpp::NodeOptions opts;
|
||||
opts.arguments(
|
||||
{
|
||||
"--ros-args",
|
||||
"--params-file", (test_resources_path / "params_by_order.yaml").string()
|
||||
});
|
||||
|
||||
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node2", "ns", opts);
|
||||
|
||||
auto * node_parameters =
|
||||
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
|
||||
node->get_node_parameters_interface().get());
|
||||
ASSERT_NE(nullptr, node_parameters);
|
||||
|
||||
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
|
||||
EXPECT_EQ(3u, parameter_overrides.size());
|
||||
EXPECT_EQ(parameter_overrides.at("a_value").get<std::string>(), "last_one_win");
|
||||
EXPECT_EQ(parameter_overrides.at("foo").get<std::string>(), "foo");
|
||||
EXPECT_EQ(parameter_overrides.at("bar").get<std::string>(), "bar");
|
||||
}
|
||||
|
||||
TEST_F(TestNodeParameters, complicated_wildcards)
|
||||
{
|
||||
rclcpp::NodeOptions opts;
|
||||
opts.arguments(
|
||||
{
|
||||
"--ros-args",
|
||||
"--params-file", (test_resources_path / "complicated_wildcards.yaml").string()
|
||||
});
|
||||
|
||||
{
|
||||
// regex matched: /**/foo/*/bar
|
||||
std::shared_ptr<rclcpp::Node> node =
|
||||
std::make_shared<rclcpp::Node>("node2", "/a/b/c/foo/d/bar", opts);
|
||||
|
||||
auto * node_parameters =
|
||||
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
|
||||
node->get_node_parameters_interface().get());
|
||||
ASSERT_NE(nullptr, node_parameters);
|
||||
|
||||
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
|
||||
EXPECT_EQ(2u, parameter_overrides.size());
|
||||
EXPECT_EQ(parameter_overrides.at("foo").get<std::string>(), "foo");
|
||||
EXPECT_EQ(parameter_overrides.at("bar").get<std::string>(), "bar");
|
||||
}
|
||||
|
||||
{
|
||||
// regex not matched: /**/foo/*/bar
|
||||
std::shared_ptr<rclcpp::Node> node =
|
||||
std::make_shared<rclcpp::Node>("node2", "/a/b/c/foo/bar", opts);
|
||||
|
||||
auto * node_parameters =
|
||||
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
|
||||
node->get_node_parameters_interface().get());
|
||||
ASSERT_NE(nullptr, node_parameters);
|
||||
|
||||
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
|
||||
EXPECT_EQ(0u, parameter_overrides.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/parameter_map.hpp"
|
||||
@@ -353,3 +354,132 @@ TEST(Test_parameter_map_from, string_array_param_value)
|
||||
c_params->params[0].parameter_values[0].string_array_value = NULL;
|
||||
rcl_yaml_node_struct_fini(c_params);
|
||||
}
|
||||
|
||||
TEST(Test_parameter_map_from, one_node_one_param_by_node_fqn)
|
||||
{
|
||||
rcl_params_t * c_params = make_params({"foo"});
|
||||
make_node_params(c_params, 0, {"string_param"});
|
||||
|
||||
std::string hello_world = "hello world";
|
||||
char * c_hello_world = new char[hello_world.length() + 1];
|
||||
std::snprintf(c_hello_world, hello_world.size() + 1, "%s", hello_world.c_str());
|
||||
c_params->params[0].parameter_values[0].string_value = c_hello_world;
|
||||
|
||||
rclcpp::ParameterMap map = rclcpp::parameter_map_from(c_params, "/foo");
|
||||
const std::vector<rclcpp::Parameter> & params = map.at("/foo");
|
||||
EXPECT_STREQ("string_param", params.at(0).get_name().c_str());
|
||||
EXPECT_STREQ(hello_world.c_str(), params.at(0).get_value<std::string>().c_str());
|
||||
|
||||
c_params->params[0].parameter_values[0].string_value = NULL;
|
||||
delete[] c_hello_world;
|
||||
rcl_yaml_node_struct_fini(c_params);
|
||||
}
|
||||
|
||||
TEST(Test_parameter_map_from, multi_nodes_same_param_name_by_node_fqn)
|
||||
{
|
||||
std::vector<std::string> node_names_keys = {
|
||||
"/**", // index: 0
|
||||
"/*", // index: 1
|
||||
"/**/node", // index: 2
|
||||
"/*/node", // index: 3
|
||||
"/ns/node" // index: 4
|
||||
};
|
||||
|
||||
rcl_params_t * c_params = make_params(node_names_keys);
|
||||
|
||||
std::vector<char *> param_values;
|
||||
for (size_t i = 0; i < node_names_keys.size(); ++i) {
|
||||
make_node_params(c_params, i, {"string_param"});
|
||||
std::string hello_world = "hello world" + std::to_string(i);
|
||||
char * c_hello_world = new char[hello_world.length() + 1];
|
||||
std::snprintf(c_hello_world, hello_world.size() + 1, "%s", hello_world.c_str());
|
||||
c_params->params[i].parameter_values[0].string_value = c_hello_world;
|
||||
param_values.push_back(c_hello_world);
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::vector<size_t>> node_fqn_expected = {
|
||||
{"/ns/foo/another_node", {0}},
|
||||
{"/another", {0, 1}},
|
||||
{"/node", {0, 1, 2}},
|
||||
{"/another_ns/node", {0, 2, 3}},
|
||||
{"/ns/node", {0, 2, 3, 4}},
|
||||
};
|
||||
|
||||
for (auto & kv : node_fqn_expected) {
|
||||
rclcpp::ParameterMap map = rclcpp::parameter_map_from(c_params, kv.first.c_str());
|
||||
const std::vector<rclcpp::Parameter> & params = map.at(kv.first);
|
||||
|
||||
EXPECT_EQ(kv.second.size(), params.size());
|
||||
for (size_t i = 0; i < params.size(); ++i) {
|
||||
std::string param_value = "hello world" + std::to_string(kv.second[i]);
|
||||
EXPECT_STREQ("string_param", params.at(i).get_name().c_str());
|
||||
EXPECT_STREQ(param_value.c_str(), params.at(i).get_value<std::string>().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < node_names_keys.size(); ++i) {
|
||||
c_params->params[i].parameter_values[0].string_value = NULL;
|
||||
}
|
||||
for (auto c_hello_world : param_values) {
|
||||
delete[] c_hello_world;
|
||||
}
|
||||
rcl_yaml_node_struct_fini(c_params);
|
||||
}
|
||||
|
||||
TEST(Test_parameter_map_from, multi_nodes_diff_param_name_by_node_fqn)
|
||||
{
|
||||
std::vector<std::string> node_names_keys = {
|
||||
"/**", // index: 0
|
||||
"/*", // index: 1
|
||||
"/**/node", // index: 2
|
||||
"/*/node", // index: 3
|
||||
"/ns/**", // index: 4
|
||||
"/ns/*", // index: 5
|
||||
"/ns/**/node", // index: 6
|
||||
"/ns/*/node", // index: 7
|
||||
"/ns/**/a/*/node", // index: 8
|
||||
"/ns/node" // index: 9
|
||||
};
|
||||
|
||||
rcl_params_t * c_params = make_params(node_names_keys);
|
||||
|
||||
for (size_t i = 0; i < node_names_keys.size(); ++i) {
|
||||
std::string param_name = "string_param" + std::to_string(i);
|
||||
make_node_params(c_params, i, {param_name});
|
||||
}
|
||||
|
||||
std::string hello_world = "hello world";
|
||||
char * c_hello_world = new char[hello_world.length() + 1];
|
||||
std::snprintf(c_hello_world, hello_world.size() + 1, "%s", hello_world.c_str());
|
||||
|
||||
for (size_t i = 0; i < node_names_keys.size(); ++i) {
|
||||
c_params->params[i].parameter_values[0].string_value = c_hello_world;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::vector<size_t>> node_fqn_expected = {
|
||||
{"/ns/node", {0, 2, 3, 4, 5, 6, 9}},
|
||||
{"/node", {0, 1, 2}},
|
||||
{"/ns/foo/node", {0, 2, 4, 6, 7}},
|
||||
{"/ns/foo/a/node", {0, 2, 4, 6}},
|
||||
{"/ns/foo/a/bar/node", {0, 2, 4, 6, 8}},
|
||||
{"/ns/a/bar/node", {0, 2, 4, 6, 8}},
|
||||
{"/ns/foo/zoo/a/bar/node", {0, 2, 4, 6, 8}},
|
||||
};
|
||||
|
||||
for (auto & kv : node_fqn_expected) {
|
||||
rclcpp::ParameterMap map = rclcpp::parameter_map_from(c_params, kv.first.c_str());
|
||||
const std::vector<rclcpp::Parameter> & params = map.at(kv.first);
|
||||
EXPECT_EQ(kv.second.size(), params.size());
|
||||
for (size_t i = 0; i < params.size(); ++i) {
|
||||
std::string param_name = "string_param" + std::to_string(kv.second[i]);
|
||||
EXPECT_STREQ(param_name.c_str(), params.at(i).get_name().c_str());
|
||||
EXPECT_STREQ(hello_world.c_str(), params.at(i).get_value<std::string>().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < node_names_keys.size(); ++i) {
|
||||
c_params->params[i].parameter_values[0].string_value = NULL;
|
||||
}
|
||||
delete[] c_hello_world;
|
||||
rcl_yaml_node_struct_fini(c_params);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
/**/foo/*/bar:
|
||||
node2:
|
||||
ros__parameters:
|
||||
foo: "foo"
|
||||
bar: "bar"
|
||||
@@ -0,0 +1,16 @@
|
||||
/**:
|
||||
node2:
|
||||
ros__parameters:
|
||||
a_value: "first"
|
||||
foo: "foo"
|
||||
|
||||
/ns:
|
||||
node2:
|
||||
ros__parameters:
|
||||
a_value: "second"
|
||||
bar: "bar"
|
||||
|
||||
/*:
|
||||
node2:
|
||||
ros__parameters:
|
||||
a_value: "last_one_win"
|
||||
57
rclcpp/test/resources/test_node_parameters/wildcards.yaml
Normal file
57
rclcpp/test/resources/test_node_parameters/wildcards.yaml
Normal file
@@ -0,0 +1,57 @@
|
||||
/**:
|
||||
ros__parameters:
|
||||
full_wild: "full_wild"
|
||||
|
||||
/**:
|
||||
node2:
|
||||
ros__parameters:
|
||||
namespace_wild: "namespace_wild"
|
||||
|
||||
/**/node2:
|
||||
ros__parameters:
|
||||
namespace_wild_another: "namespace_wild_another"
|
||||
|
||||
/*:
|
||||
node2:
|
||||
ros__parameters:
|
||||
namespace_wild_one_star: "namespace_wild_one_star"
|
||||
|
||||
ns:
|
||||
"*":
|
||||
ros__parameters:
|
||||
node_wild_in_ns: "node_wild_in_ns"
|
||||
|
||||
/ns/*:
|
||||
ros__parameters:
|
||||
node_wild_in_ns_another: "node_wild_in_ns_another"
|
||||
|
||||
ns:
|
||||
node2:
|
||||
ros__parameters:
|
||||
explicit_in_ns: "explicit_in_ns"
|
||||
|
||||
"*":
|
||||
ros__parameters:
|
||||
node_wild_no_ns: "node_wild_no_ns"
|
||||
|
||||
node2:
|
||||
ros__parameters:
|
||||
explicit_no_ns: "explicit_no_ns"
|
||||
|
||||
ns:
|
||||
nodeX:
|
||||
ros__parameters:
|
||||
should_not_appear: "incorrect_node_name"
|
||||
|
||||
/**/nodeX:
|
||||
ros__parameters:
|
||||
should_not_appear: "incorrect_node_name"
|
||||
|
||||
nsX:
|
||||
node2:
|
||||
ros__parameters:
|
||||
should_not_appear: "incorrect_namespace"
|
||||
|
||||
/nsX/*:
|
||||
ros__parameters:
|
||||
should_not_appear: "incorrect_namespace"
|
||||
@@ -3,6 +3,9 @@ Changelog for package rclcpp_action
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
16.0.2 (2022-11-07)
|
||||
-------------------
|
||||
|
||||
16.0.1 (2022-04-13)
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -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>16.0.1</version>
|
||||
<version>16.0.2</version>
|
||||
<description>Adds action APIs for C++.</description>
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
<maintainer email="jacob@openrobotics.org">Jacob Perron</maintainer>
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
Changelog for package rclcpp_components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
16.0.2 (2022-11-07)
|
||||
-------------------
|
||||
|
||||
16.0.1 (2022-04-13)
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -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>16.0.1</version>
|
||||
<version>16.0.2</version>
|
||||
<description>Package containing tools for dynamically loadable components</description>
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
<maintainer email="jacob@openrobotics.org">Jacob Perron</maintainer>
|
||||
|
||||
@@ -3,6 +3,9 @@ Changelog for package rclcpp_lifecycle
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
16.0.2 (2022-11-07)
|
||||
-------------------
|
||||
|
||||
16.0.1 (2022-04-13)
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -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>16.0.1</version>
|
||||
<version>16.0.2</version>
|
||||
<description>Package containing a prototype for lifecycle implementation</description>
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
<maintainer email="jacob@openrobotics.org">Jacob Perron</maintainer>
|
||||
|
||||
Reference in New Issue
Block a user