Simplifying how to declare parameters in ROS 2

From our point of view, loading structured data as parameter is a hard requirement.
We tried pushing this, by implementing recursive message support, which would allow us to use tree like parameter messages (see fix: Generate correct code for nested arrays of own type by jmachowinski · Pull Request #748 · ros2/rosidl · GitHub).

At some point there was no progress any more on the merge request and as we needed to move forward, we dumped the whole ros parameter system and implemented our own.

Here is an overview of what we did, as you might wanna pick the good parts of it :

A common package is defined, from which parameters are loaded (config_pkg). This package is shared across machines builds, and may not have local modifications. A parameter file is expected to be found under $(find_shared config_pkg)/namespace/node_name.yaml of the requesting node.

Node parameter files may include other yaml files. This is a common use case for us, as some parameters are shared across multiple nodes, and we did not want to have multiple copies around.
e.g. :

navigation:
    includes:
        - /navigation/navigation.yaml
hal:
    includes:
        - /hal/hardware_config.yaml

pre_spinup_time_info:
  help: time a wheel shall start to spin up before it is touched by a parcel
pre_spinup_time: 0.2

On the node side (cpp only) we use a template system similar to the toMsg/fromMsg one of tf2. This template system allows us to have common headers for common datatypes like Eigen::Vector3d, rclcpp::Duration etc. There are also common headers, to parse containers (vectors, maps) of datatypes.
In the node this looks like this :

minStateStdDev:
  pose:
    x: 0.005
    y: 0.005
    orientation: 1 # orientation in degrees
  velocity:
    x: 0.005
    y: 0.005
    orientation: 1 # orientation in degrees
  size:
    x: 0.005
    y: 0.005
    z: 0.005

struct PoseParameters
{
    Eigen::Vector2d translation;
    cm::Angled rotation;
};

struct StateParameters
{
    PoseParameters pose;
    PoseParameters velocity;
    Eigen::Vector3d size;
};

template<>
struct ParamConversion<passenger_state_estimation::StateParameters>
{
    static passenger_state_estimation::StateParameters from(const YAML::Node& param)
    {
        if (!param.IsDefined())
        {
            throw ConfigException::elementNotDefined();
        }
        checkType(param, YAML::NodeType::Map);

        return passenger_state_estimation::StateParameters{
            getElem<passenger_state_estimation::PoseParameters>(param, "pose"),
            getElem<passenger_state_estimation::PoseParameters>(param, "velocity"),
            getElem<Eigen::Vector3d>(param, "size")};
    }
};

param = nodeBase.declareParameter<StateParameters>("minStateStdDev")
StateParameters p = param->getValue()

Together with this we also developed a web based configuration tool, that allows the colleges that are not from the software department, to change parameter. For this purpose, each yaml parameter may be annotated with an info entry, that is shown in the configuration tool. E.g.:

angular_speed_base_std_dev_info:
  help: base standard deviation for the angular speed
  unit: deg/s
angular_speed_base_std_dev: 10
2 Likes