Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7aff0ffc56 | ||
|
|
0b606918d0 | ||
|
|
81d6f897a2 | ||
|
|
206e0fd4fe | ||
|
|
4fc379196d | ||
|
|
2f0db6c802 | ||
|
|
48068130ed | ||
|
|
54c2a8ac5b | ||
|
|
468cbab1aa |
@@ -8,10 +8,10 @@ rclcpp provides the standard C++ API for interacting with ROS 2.
|
||||
|
||||
`#include "rclcpp/rclcpp.hpp"` allows use of the most common elements of the ROS 2 system.
|
||||
|
||||
Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) for a complete list of its main components.
|
||||
Visit the [rclcpp API documentation](http://docs.ros2.org/galactic/api/rclcpp/) for a complete list of its main components.
|
||||
|
||||
### Examples
|
||||
|
||||
The ROS 2 tutorials [Writing a simple publisher and subscriber](https://docs.ros.org/en/rolling/Tutorials/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html).
|
||||
and [Writing a simple service and client](https://docs.ros.org/en/rolling/Tutorials/Writing-A-Simple-Cpp-Service-And-Client.html)
|
||||
The ROS 2 tutorials [Writing a simple publisher and subscriber](https://docs.ros.org/en/galactic/Tutorials/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html).
|
||||
and [Writing a simple service and client](https://docs.ros.org/en/galactic/Tutorials/Writing-A-Simple-Cpp-Service-And-Client.html)
|
||||
contain some examples of rclcpp APIs in use.
|
||||
|
||||
@@ -2,6 +2,19 @@
|
||||
Changelog for package rclcpp
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
9.2.2 (2022-12-06)
|
||||
------------------
|
||||
* Fix returning invalid namespace if sub_namespace is empty (`#1810 <https://github.com/ros2/rclcpp/issues/1810>`_)
|
||||
* use regex for wildcard matching (`#1987 <https://github.com/ros2/rclcpp/issues/1987>`_)
|
||||
* Add statistics for handle_loaned_message (`#1933 <https://github.com/ros2/rclcpp/issues/1933>`_)
|
||||
* Contributors: Aaron Lipinski, Barry Xu, Chen Lihui, M. Hofstätter
|
||||
|
||||
9.2.1 (2022-04-28)
|
||||
------------------
|
||||
* Add test-dep ament_cmake_google_benchmark (`#1904 <https://github.com/ros2/rclcpp/issues/1904>`_) (`#1909 <https://github.com/ros2/rclcpp/issues/1909>`_)
|
||||
* Use parantheses around logging macro parameter (`#1820 <https://github.com/ros2/rclcpp/issues/1820>`_) (`#1822 <https://github.com/ros2/rclcpp/issues/1822>`_)
|
||||
* Contributors: mergify[bot]
|
||||
|
||||
9.2.0 (2021-09-17)
|
||||
------------------
|
||||
* Added thread safe for_each_callback_group method (`#1741 <https://github.com/ros2/rclcpp/issues/1741>`_)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -295,11 +295,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<CallbackMessageT *>(loaned_message);
|
||||
// message is loaned, so we have to make sure that the deleter does not deallocate the message
|
||||
auto sptr = std::shared_ptr<CallbackMessageT>(
|
||||
typed_message, [](CallbackMessageT * 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.
|
||||
|
||||
@@ -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>9.2.0</version>
|
||||
<version>9.2.2</version>
|
||||
<description>The ROS client library in C++.</description>
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
<maintainer email="mabel@openrobotics.org">Mabel Zhang</maintainer>
|
||||
@@ -37,6 +37,7 @@
|
||||
<depend>tracetools</depend>
|
||||
|
||||
<test_depend>ament_cmake_gmock</test_depend>
|
||||
<test_depend>ament_cmake_google_benchmark</test_depend>
|
||||
<test_depend>ament_cmake_gtest</test_depend>
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>ament_lint_common</test_depend>
|
||||
|
||||
@@ -149,7 +149,7 @@ def get_rclcpp_suffix_from_features(features):
|
||||
@[ if params]@
|
||||
@(''.join([' ' + p + ', \\\n' for p in params if p != stream_arg]))@
|
||||
@[ end if]@
|
||||
logger.get_name(), \
|
||||
(logger).get_name(), \
|
||||
@[ if 'stream' not in feature_combination]@
|
||||
__VA_ARGS__); \
|
||||
@[ else]@
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,12 @@ extend_sub_namespace(const std::string & existing_sub_namespace, const std::stri
|
||||
extension.c_str(),
|
||||
"a sub-namespace should not have a leading /",
|
||||
0);
|
||||
} else if (existing_sub_namespace.empty() && extension.empty()) {
|
||||
throw rclcpp::exceptions::NameValidationError(
|
||||
"sub_namespace",
|
||||
extension.c_str(),
|
||||
"sub-nodes should not extend nodes by an empty sub-namespace",
|
||||
0);
|
||||
}
|
||||
|
||||
std::string new_sub_namespace;
|
||||
@@ -86,7 +92,11 @@ create_effective_namespace(const std::string & node_namespace, const std::string
|
||||
// and do not need trimming of `/` and other things, as they were validated
|
||||
// in other functions already.
|
||||
|
||||
if (node_namespace.back() == '/') {
|
||||
// A node may not have a sub_namespace if it is no sub_node. In this case,
|
||||
// just return the original namespace
|
||||
if (sub_namespace.empty()) {
|
||||
return node_namespace;
|
||||
} else if (node_namespace.back() == '/') {
|
||||
// this is the special case where node_namespace is just `/`
|
||||
return node_namespace + sub_namespace;
|
||||
} else {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,6 +229,12 @@ TEST_F(TestLoggingMacros, test_throttle) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestLoggingMacros, test_parameter_expression) {
|
||||
RCLCPP_DEBUG_STREAM(*&g_logger, "message");
|
||||
EXPECT_EQ(1u, g_log_calls);
|
||||
EXPECT_EQ("message", g_last_log_event.message);
|
||||
}
|
||||
|
||||
bool log_function(rclcpp::Logger logger)
|
||||
{
|
||||
RCLCPP_INFO(logger, "successful log");
|
||||
|
||||
@@ -99,6 +99,7 @@ TEST_F(TestNode, get_name_and_namespace) {
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
EXPECT_STREQ("my_node", node->get_name());
|
||||
EXPECT_STREQ("/ns", node->get_namespace());
|
||||
EXPECT_STREQ("/ns", node->get_effective_namespace().c_str());
|
||||
EXPECT_STREQ("/ns/my_node", node->get_fully_qualified_name());
|
||||
}
|
||||
{
|
||||
@@ -113,30 +114,35 @@ TEST_F(TestNode, get_name_and_namespace) {
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "ns");
|
||||
EXPECT_STREQ("my_node", node->get_name());
|
||||
EXPECT_STREQ("/ns", node->get_namespace());
|
||||
EXPECT_STREQ("/ns", node->get_effective_namespace().c_str());
|
||||
EXPECT_STREQ("/ns/my_node", node->get_fully_qualified_name());
|
||||
}
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node");
|
||||
EXPECT_STREQ("my_node", node->get_name());
|
||||
EXPECT_STREQ("/", node->get_namespace());
|
||||
EXPECT_STREQ("/", node->get_effective_namespace().c_str());
|
||||
EXPECT_STREQ("/my_node", node->get_fully_qualified_name());
|
||||
}
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "");
|
||||
EXPECT_STREQ("my_node", node->get_name());
|
||||
EXPECT_STREQ("/", node->get_namespace());
|
||||
EXPECT_STREQ("/", node->get_effective_namespace().c_str());
|
||||
EXPECT_STREQ("/my_node", node->get_fully_qualified_name());
|
||||
}
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/my/ns");
|
||||
EXPECT_STREQ("my_node", node->get_name());
|
||||
EXPECT_STREQ("/my/ns", node->get_namespace());
|
||||
EXPECT_STREQ("/my/ns", node->get_effective_namespace().c_str());
|
||||
EXPECT_STREQ("/my/ns/my_node", node->get_fully_qualified_name());
|
||||
}
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "my/ns");
|
||||
EXPECT_STREQ("my_node", node->get_name());
|
||||
EXPECT_STREQ("/my/ns", node->get_namespace());
|
||||
EXPECT_STREQ("/my/ns", node->get_effective_namespace().c_str());
|
||||
EXPECT_STREQ("/my/ns/my_node", node->get_fully_qualified_name());
|
||||
}
|
||||
{
|
||||
@@ -275,6 +281,13 @@ TEST_F(TestNode, subnode_construction_and_destruction) {
|
||||
auto subnode = node->create_sub_node("~sub_ns");
|
||||
}, rclcpp::exceptions::InvalidNamespaceError);
|
||||
}
|
||||
{
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
auto subnode = node->create_sub_node("");
|
||||
}, rclcpp::exceptions::NameValidationError);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestNode, get_logger) {
|
||||
|
||||
@@ -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,12 @@ Changelog for package rclcpp_action
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
9.2.2 (2022-12-06)
|
||||
------------------
|
||||
|
||||
9.2.1 (2022-04-28)
|
||||
------------------
|
||||
|
||||
9.2.0 (2021-09-17)
|
||||
------------------
|
||||
* Fixed a bug where it would occasionally miss a goal result, which was caused by race condition (`#1677 <https://github.com/ros2/rclcpp/issues/1677>`_) (`#1683 <https://github.com/ros2/rclcpp/issues/1683>`_)
|
||||
|
||||
@@ -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>9.2.0</version>
|
||||
<version>9.2.2</version>
|
||||
<description>Adds action APIs for C++.</description>
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
<maintainer email="mabel@openrobotics.org">Mabel Zhang</maintainer>
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
Changelog for package rclcpp_components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
9.2.2 (2022-12-06)
|
||||
------------------
|
||||
|
||||
9.2.1 (2022-04-28)
|
||||
------------------
|
||||
|
||||
9.2.0 (2021-09-17)
|
||||
------------------
|
||||
|
||||
|
||||
@@ -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>9.2.0</version>
|
||||
<version>9.2.2</version>
|
||||
<description>Package containing tools for dynamically loadable components</description>
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
<maintainer email="mabel@openrobotics.org">Mabel Zhang</maintainer>
|
||||
|
||||
@@ -3,6 +3,12 @@ Changelog for package rclcpp_lifecycle
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
9.2.2 (2022-12-06)
|
||||
------------------
|
||||
|
||||
9.2.1 (2022-04-28)
|
||||
------------------
|
||||
|
||||
9.2.0 (2021-09-17)
|
||||
------------------
|
||||
* Added thread safe for_each_callback_group method (`#1741 <https://github.com/ros2/rclcpp/issues/1741>`_)
|
||||
|
||||
@@ -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>9.2.0</version>
|
||||
<version>9.2.2</version>
|
||||
<description>Package containing a prototype for lifecycle implementation</description>
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
<maintainer email="mabel@openrobotics.org">Mabel Zhang</maintainer>
|
||||
|
||||
Reference in New Issue
Block a user