I thought this is an interesting question so I had a look around. Firstly, the documentation of declare_parameter
states:
The name and type in the given rcl_interfaces::msg::ParameterDescriptor are ignored, and should be specified using the name argument to this function and the default value's type instead.
When we look through the code, we can see that the descriptor name is indeed always overridden by the name value passed as the first argument (here for parameters that do not have a default/initial value and here for parameters that do):
parameter_infos[name].descriptor.name = name;
Trying to set a different name in the descriptor for different variants of declare_parameter
like so:
auto param1 = declare_parameter("param1");
auto param2_desc = rcl_interfaces::msg::ParameterDescriptor{};
param2_desc.name = "param2desc";
auto param2 = declare_parameter<int>("param2", 0, param2_desc);
auto param3_desc = rcl_interfaces::msg::ParameterDescriptor{};
param3_desc.name = "param3desc";
auto param3 = declare_parameter<int>("param3", rclcpp::ParameterType::PARAMETER_INTEGER, param3_desc);
auto param4_desc = rcl_interfaces::msg::ParameterDescriptor{};
param3_desc.name = "param4desc";
auto param4 = declare_parameter<int>("param4", rclcpp::PARAMETER_NOT_SET, param4_desc);
and then listing them, shows that indeed in each case the name given in the descriptor is ignored:
$ ros2 param list
/param_name_test:
param1
param2
param3
param4
As for why this seeming redundancy is there I couldn't directly find a source, but I'd hazard the guess that it is to enforce providing a name (and type).
When you run ros2 describe /yournode yourparam
, what happens underneath is that the hidden describe_parameters
service is called on yournode
, which returns a list of ParameterDescriptor
s.
This is the same ParameterDescriptor
message type as that you can pass into declare_parameter
. So this message type needs to have al the information in it, including the parameter name.
However, ROS 2 messages do not have a way to enforce that all values are set; you could create an empty descriptor like ParamaterDescriptor{}
and pass it in, which would have an empty string as the default value for name
. ROS 2 could check this at runtime and throw an exception, but it's better to catch this earlier, which is I suspect why it forces you to give the name (and type) explicitly and then set that on the descriptor, so that you can't forget, or at least so that the compiler will already tell you much sooner.
It is of course still possible to erroneously pass an empty string as name, and ROS 2 does check for that at runtime, but it's much harder to do that accidentally.