Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get parameter map #575

Merged
merged 5 commits into from
Jan 16, 2019
Merged

Get parameter map #575

merged 5 commits into from
Jan 16, 2019

Conversation

clalancette
Copy link
Contributor

@clalancette clalancette commented Oct 29, 2018

This PR adds the ability to get a std::map set of key-value pairs of parameters. In this case, parameters that form part of a map are all of the form:

param.x
param.y

Assuming param.x has value 0.1 and param.y has value 1.5, then calling this API like:

std::map<std::string, double> params;
node->get_parameter("param", params);

Would fill in the params map with keys of x and y with values of 0.1 and 1.5, respectively. There is also a set_parameter_if_not_set that works much in the same way for setting values. Tests for this new functionality are added in a new test file; I'll move the rest of the "local" parameter tests from system_tests once this is in. This should solve #529 , and will unblock ros2/teleop_twist_joy#8

connects to #529

@clalancette clalancette added the in progress Actively being worked on (Kanban column) label Oct 29, 2018
@clalancette clalancette added in review Waiting for review (Kanban column) and removed in progress Actively being worked on (Kanban column) labels Oct 29, 2018
@clalancette
Copy link
Contributor Author

clalancette commented Oct 29, 2018

CI (up to test_rclcpp, testing only rclcpp and test_rclcpp):

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

@@ -277,6 +277,12 @@ class Node : public std::enable_shared_from_this<Node>
const std::string & name,
const ParameterT & value);

template<typename MapValueT>
void
set_parameter_if_not_set(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the methods sets multiple parameters the method name should be plural: set_parameters_if_not_set.

Same for get_parameter() below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel strongly about the name, but I will point out that in ROS1 all of the methods were named the same, regardless of whether they were setting a map, a vector, or a single value. I think there is value to this here as well, since there is only "one" name to remember, regardless of the type you want to set. However, if you insist, I will change the name to be plural.

@@ -303,6 +309,24 @@ class Node : public std::enable_shared_from_this<Node>
bool
get_parameter(const std::string & name, ParameterT & parameter) const;

/// Assign the value of the map parameter if set into the values argument.
/**
* Parameter names that are part of a map are of the form "name.member".
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the signature I would rather not pass name here. Each key in the map can already be a "full" name. Otherwise this function prohibits to set two parameters in different "branches" of the "naming tree".

Same below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While that is true (and makes some sense for set), it doesn't really make much sense for get. If we just make it so that there is no "grouping" with this API, then there is little reason to add this API; we can do the same thing by calling get_parameters with a vector of names. The explicit purpose of the map-based one is to have a group of variables that we can get into a single map. This is similar to the map-based getParam overload in ROS1.

for (const auto & val : values) {
std::string param_name = name + "." + val.first;
rclcpp::Parameter parameter;
if (!this->get_parameter(param_name, parameter)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of calling get_parameter N times I would suggest to call get_parameters() once.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can make this work using get_parameters(), but I think it is much uglier and less efficient:

template<typename MapValueT>
void
Node::set_parameter_if_not_set(
  const std::string & name,
  const std::map<std::string, MapValueT> & values)
{
  std::vector<std::string> names;

  for (const auto & val : values) {
    std::string param_name = name + "." + val.first;
    names.push_back(param_name);
  }

  std::vector<rclcpp::Parameter> params = node_parameters_->get_parameters(names);
  std::vector<rclcpp::Parameter> params_to_set;

  for (const auto & val : values) {
    std::string param_name = name + "." + val.first;
    if (std::find_if(params.begin(), params.end(),
                     [&param_name](const rclcpp::Parameter& param) {
                       return param.get_name() == param_name;
                     }) == params.end()) {
      params_to_set.push_back(rclcpp::Parameter(param_name, val.second));
    }
  }

  this->set_parameters(params_to_set);
}

This is due to the fact that get_parameters() returns only what is currently in the parameters, and silently ignores the ones that aren't there. Unless you can think of a way to reduce the number of loops and finds here, I'd prefer to stick to the current implementation.

@clalancette
Copy link
Contributor Author

@ros2/team There are two open questions on this PR:

  1. Whether the APIs that modify multiple values should be plural. On the one hand, this makes sense from a grammatical sense. On the other hand, all of the APIs in ROS 1 were named the same, regardless of how many items they touched (I'm thinking of getParam() and friends here). Opinions?
  2. Should we have a map-based overload at all? I think it makes it much more convenient to get a group of similar values, but it is simple syntactic sugar and all of the values can just be fetched using a vector of names. If the answer to this is "no", then I'll just close out this PR and do something different in Add in the ability to control via parameters teleop_twist_joy#8

@clalancette
Copy link
Contributor Author

(also, I'm going to close and re-open this PR to retrigger the build, since I think the failure was unrelated to this PR)

@clalancette clalancette closed this Jan 8, 2019
@clalancette clalancette reopened this Jan 8, 2019
@clalancette clalancette added in progress Actively being worked on (Kanban column) and removed in review Waiting for review (Kanban column) labels Jan 8, 2019
@tfoote
Copy link
Contributor

tfoote commented Jan 9, 2019

  1. Regarding plural vs singular I'd suggest that we go with plural we're already using the plural in most other situations like describe parameters and get_parameter_types

  2. I think that the std::map based interface is a significant improvement for searching and querying compared to a vector that exposing it will be a significant benefit to the user. It might make sense to implement it as the syntactic sugar, where the API just vectorizes the requests before interacting with the underlying implementation.

@jacobperron
Copy link
Member

  1. The vector based interface is already plural, so I think making the map based interface plural is consistent.
  2. +1 for std:map based interface.

Any parameters that have a "." in them will be considered to
be part of a "map" (though they can also be get and set
individually).  This PR adds two new template specializations
to the public node API so that it can take a map, and store
the list of values (so setting the parameter with a name of
"foo" and a key of "x" will end up with a parameter of "foo.x").
It also adds an API to get all of the keys corresponding to
a prefix, and returing that as a map (so a get of "foo" will
get all parameters that begin with "foo.").  Note that all
parameters within the map must have the same type, otherwise
an rclcpp::ParameterTypeException will be thrown.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
@clalancette
Copy link
Contributor Author

Updated to use plurals. Here's CI up to rclcpp:

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

@clalancette clalancette added in review Waiting for review (Kanban column) and removed in progress Actively being worked on (Kanban column) labels Jan 15, 2019
Copy link
Member

@wjwwood wjwwood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, only comments about documentation

rclcpp/include/rclcpp/node.hpp Show resolved Hide resolved
rclcpp/include/rclcpp/node.hpp Outdated Show resolved Hide resolved
rclcpp/include/rclcpp/node.hpp Outdated Show resolved Hide resolved
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
@clalancette clalancette merged commit 99dd031 into master Jan 16, 2019
@clalancette clalancette deleted the get-parameter-map branch January 16, 2019 19:30
@clalancette clalancette removed the in review Waiting for review (Kanban column) label Jan 16, 2019
clalancette added a commit that referenced this pull request Jan 17, 2019
* Add in the ability to get parameters in a map.

Any parameters that have a "." in them will be considered to
be part of a "map" (though they can also be get and set
individually).  This PR adds two new template specializations
to the public node API so that it can take a map, and store
the list of values (so setting the parameter with a name of
"foo" and a key of "x" will end up with a parameter of "foo.x").
It also adds an API to get all of the keys corresponding to
a prefix, and returing that as a map (so a get of "foo" will
get all parameters that begin with "foo.").  Note that all
parameters within the map must have the same type, otherwise
an rclcpp::ParameterTypeException will be thrown.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Fix style problems pointed out by uncrustify/cpplint.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Move tests for set_parameter_if_not_set/get_parameter map to rclcpp.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Rename get_parameter -> get_parameters.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Add in documentation from review.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
clalancette added a commit that referenced this pull request Jan 29, 2019
* Get parameter map (#575)

* Add in the ability to get parameters in a map.

Any parameters that have a "." in them will be considered to
be part of a "map" (though they can also be get and set
individually).  This PR adds two new template specializations
to the public node API so that it can take a map, and store
the list of values (so setting the parameter with a name of
"foo" and a key of "x" will end up with a parameter of "foo.x").
It also adds an API to get all of the keys corresponding to
a prefix, and returing that as a map (so a get of "foo" will
get all parameters that begin with "foo.").  Note that all
parameters within the map must have the same type, otherwise
an rclcpp::ParameterTypeException will be thrown.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Fix style problems pointed out by uncrustify/cpplint.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Move tests for set_parameter_if_not_set/get_parameter map to rclcpp.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Rename get_parameter -> get_parameters.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Add in documentation from review.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Use list_parameters instead of get_parameters_by_prefix.

This way, we don't break ABI in crystal.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Fix style problems.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
cho3 pushed a commit to cho3/rclcpp that referenced this pull request Jun 3, 2019
* Add in the ability to get parameters in a map.

Any parameters that have a "." in them will be considered to
be part of a "map" (though they can also be get and set
individually).  This PR adds two new template specializations
to the public node API so that it can take a map, and store
the list of values (so setting the parameter with a name of
"foo" and a key of "x" will end up with a parameter of "foo.x").
It also adds an API to get all of the keys corresponding to
a prefix, and returing that as a map (so a get of "foo" will
get all parameters that begin with "foo.").  Note that all
parameters within the map must have the same type, otherwise
an rclcpp::ParameterTypeException will be thrown.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Fix style problems pointed out by uncrustify/cpplint.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Move tests for set_parameter_if_not_set/get_parameter map to rclcpp.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Rename get_parameter -> get_parameters.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Add in documentation from review.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
nnmm pushed a commit to ApexAI/rclcpp that referenced this pull request Jul 9, 2022
* fixed package.xml

Signed-off-by: Alejandro Hernández <ahcorde@gmail.com>

* removed rosidl_generator_c dependency

Signed-off-by: Alejandro Hernández <ahcorde@gmail.com>

* rcl lifecycle restoring rosidl_generator_c dependency

Signed-off-by: Alejandro Hernández <ahcorde@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants