Parameters ShouldBe Boring
generate_parameter_library

October 20, 2023

Tyler Weaver
Staﬀ So�ware Engineer
tyler@picknik.ai0Tyler Weaver• Racing Kart Driver• MoveIt Maintainer• Rust Evangelist• Docker Skep�c1

RCLCPPParametersPart 12Ge�ng Started
int main(int argc, char ** argv){
rclcpp::init(argc, argv);
auto node = std::make_shared<rclcpp::Node>("minimal_param_node");auto my_string = node->declare_parameter("my_string", "world");
auto my_number = node->declare_parameter("my_number", 23);
rclcpp::spin(node);
rclcpp::shutdown();}3

Parameter Struct
struct Params {std::string my_string = "world";
int my_number = 23;};

4

Parameter Struct
struct Params {std::string my_string = "world";
int my_number = 23;};
int main(int argc, char ** argv){
rclcpp::init(argc, argv);
auto node = std::make_shared<rclcpp::Node>("minimal_param_node");auto params = Params{};
params.my_string = node->declare_parameter("my_string", params.my_string);
params.my_number = node->declare_parameter("my_number", params.my_number);
rclcpp::spin(node);
rclcpp::shutdown();}5

ParameterDescriptor
auto param_desc = rcl_interfaces::msg::ParameterDescriptor{};param_desc.description = "Mine!";param_desc.additional_constraints = "One of [world, base, home]";params.my_string = node->declare_parameter("my_string",
params.my_string, param_desc);

6

ParameterDescriptor
auto param_desc = rcl_interfaces::msg::ParameterDescriptor{};param_desc.description = "Mine!";param_desc.additional_constraints = "One of [world, base, home]";params.my_string = node->declare_parameter("my_string",
params.my_string, param_desc);param_desc = rcl_interfaces::msg::ParameterDescriptor{};param_desc.description = "Who controls the universe?";param_desc.additional_constraints = "A multiple of 23";params.my_number = node->declare_parameter("my_number",params.my_number, param_desc);// ...

7

Valida�on
auto const _ = node->add_on_set_parameters_callback([](std::vector<rclcpp::Parameter> const& params)-> rcl_interfaces::msg::SetParametersResult {8

Valida�on
auto const _ = node->add_on_set_parameters_callback([](std::vector<rclcpp::Parameter> const& params)-> rcl_interfaces::msg::SetParametersResult {for (auto const& param : params) {if(param.get_name() == "my_string") {auto const value = param.get_value<std::string>();9

Valida�on
auto const _ = node->add_on_set_parameters_callback([](std::vector<rclcpp::Parameter> const& params)-> rcl_interfaces::msg::SetParametersResult {for (auto const& param : params) {if(param.get_name() == "my_string") {auto const value = param.get_value<std::string>();auto const valid = std::vector<std::string>{"world", "base", "home"};if (std::find(valid.cbegin(), valid.cend(), value) == valid.end()) {auto result = rcl_interfaces::msg::SetParametersResult{};
result.successful = false;
result.reason = std::string("my_string: {").append(value).append("} not one of: [world, base, home]");return result;}

10

Copy Pasta• parameter name: 6 separate copies• declara�on: re-init descrip�on for each parameter• valida�on: convert vector to map

1130 lines of C++ boilerplate per parameter12

30 lines of C++ boilerplate per parameter
Before handling of dynamic parameters

12generate_parameter_library
Paul Gesel @pac48

Part 213

YAML
minimal_param_node:
my_string: {type: string,description: "Mine!",validation: {one_of<>: [["world", "base", "home"]]}}my_number: {type: int,description: "Mine!",validation: {multiple_of_23: []}}14

Valida�on~/ws$ ros2 run ...
terminate called after throwing an instance of'rclcpp::exceptions::InvalidParameterValueException'what(): Invalid value set during initialization for parameter 'my_string':
Parameter 'my_string' with the value 'place' is not in the set'[world, base, home]'~/ws$ ros2 param set /node_name my_string "hello"
Setting parameter failed: Parameter 'my_string' with the value 'hello' is
not in the set '[world, base, home]'

15

CMake Module
find_package(generate_parameter_library REQUIRED)
generate_parameter_library(minimal_param_node_parameters
src/minimal_param_node.yaml)
add_executable(minimal_node src/minimal_param_node.cpp)
target_link_libraries(minimal_node PRIVATE
rclcpp::rclcpp
minimal_param_node_parameters)16C++ Usage#include <rclcpp/rclcpp.hpp>#include "minimal_param_node_parameters.hpp"
int main(int argc, char * argv[]){
rclcpp::init(argc, argv);
auto node = std::make_shared<rclcpp::Node>("minimal_param_node");auto param_listener =std::make_shared<minimal_param_node::ParamListener>(node);
auto params = param_listener->get_params();// ...

17

Built-In Valida�on Func�ons• bounds (inclusive)• less than• greater than• less than or equal• greater than or equal

18Built-In Valida�on Func�ons• bounds (inclusive)• less than• greater than• less than or equal• greater than or equal• ﬁxed string/array length• size of string/array length greater than• size of string/array length less than• array contains no duplicates• array is a subset of another array• bounds checking for elements of an array

18

Custom Valida�on#include <rclcpp/rclcpp.hpp>#include <fmt/core.h>#include <tl_expected/expected.hpp>
tl::expected<void, std::string> multiple_of_23(rclcpp::Parameter const& parameter) {int param_value = parameter.as_int();
if (param_value % 23 != 0) {return tl::make_unexpected(fmt::format("Invalid value '{}' for parameter {}. Must be multiple of 23.",param_value, parameter.get_name());}
return {};}19

Other Killer Features• Dynamic parameters• Genera�on of RCLPY Parameter Libraries• Genera�on of Markdown Docs
• Examples and docs atgithub.com/PickNikRobo�cs/generate_parameter_library• Released on Humble, Iron, and Rolling20

Contribu�ons• agonzat• bijoua29• Błażej Sowa
• Bruno-Pier• Chance Cardona• Charles Cross• Chien shao-yu• Chris Thrasher• chriseichmann• Christoph Fröhlich• Denis Stogl• Diogo Almeida• Michael Carroll• Felix Exner (fexner) • Michael Wrock• Florian Vahl
• mosfet80• g-argyropoulos• Paul Gesel• Griswald Brooks• Sai Kishor Kothakota• Guelakais• Sco� K Logan• GuiHome• Siddharth Saha
• Jan Gutsche• sprenger120• light-tech• Steven! Ragnarök• Marq Rasmussen• Tony Najjar• Masaya Kataoka• Tyler Weaver
21

Users• MoveIt 2• ros2_control• PickNik Clients• you?

22

Boring?
Part 323

Why so many parameters?

• Users use defaults for most parameters24

Why so many parameters?

• Users use defaults for most parameters• Authors only test default values

24Why so many parameters?

• Users use defaults for most parameters• Authors only test default values• Permuta�ons of parameters grow exponen�ally24

Why so many parameters?

• Users use defaults for most parameters• Authors only test default values• Permuta�ons of parameters grow exponen�ally• The more complex your interface the less useful your abstrac�on24

Why so many parameters?

• Users use defaults for most parameters• Authors only test default values• Permuta�ons of parameters grow exponen�ally• The more complex your interface the less useful your abstrac�on• Resist the urge to expose interior details as parameters24

What is a good parameter?

• Express user intent (latency or throughput)25

What is a good parameter?

• Express user intent (latency or throughput)• Details like buﬀer sizes scale with hardware

25

What is a good parameter?

• Express user intent (latency or throughput)• Details like buﬀer sizes scale with hardware• Leave the door open to improvements in behavior for the user25

Ques�ons?

Slides rendered using Elsietylerjw.dev/posts/roscon23-parameters/

26