rclcpp: Cannot load yaml config to composable node in dashing

Bug report

I used to load a yaml configuration file into a composable node with ROS crystal that is started from a standalone executable. This stopped working after porting to dashing. The lack of parameter file loading examples for composable nodes also makes debugging this more difficult.

Required Info:

  • Operating System: Ubuntu 18.04
  • Installation type: binary
  • Version or commit hash: dashing
  • DDS implementation: Fast-RTPS
  • Client library (if applicable): rclcpp

Steps to reproduce issue

  • create a node, e.g. AprilTag2Node::AprilTag2Node(rclcpp::NodeOptions options) : Node("apriltag2", "apriltag", options.use_intra_process_comms(true))
  • create a config config.yaml with with parameters:
apriltag:                           # namespace
    apriltag2:                      # node name
        ros__parameters:
            image_transport: raw
            size: 0.162
            parameter1: 89
            parameter2: 56.89
  • load a yaml file like: ros2 run your_package your_node __params:=<path_to>/config.yaml

Expected behavior

A call to get_parameter_or<double>("size", tag_edge_size, 2.0); within the node should provide the value of the parameter in the yaml file.

Actual behavior

The default parameter is returned.

Additional information

The main change for porting from crystal to dashing is the adaptation of the node options:

-AprilTag2Node::AprilTag2Node() : Node("apriltag2", "apriltag", true) {
+AprilTag2Node::AprilTag2Node(rclcpp::NodeOptions options) : Node("apriltag2", "apriltag", options.use_intra_process_comms(true)) {

This should keep the namespace intact and not change the behaviour of setting parameters.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 15 (5 by maintainers)

Commits related to this issue

Most upvoted comments

@mjcarroll any update on this? The last of the discussion looks to be before the dashing release. We’re coming up on Foxy and this feels like something that should be included in the next LTS.

Hey @christianrauch, @wjwwood and I spent some time discussing this today, and here’s the conclusion for the dashing release:

The way that you are currently passing the parameters to the load command ros2 component load /ComponentManager test Test -r __params:=ros2 pkg prefix test/share/test/cfg/demo.yaml is essentially a remapping argument. The parameter file that is read in that case has to have the parameters nested under node_name/ros__parameters in the YAML file, which is consistent with how a standalone node will work. In this case though, the container does not receive the parameters via the parameters field in the service call, but instead receives a remapping argument for __params.

The current implementation of the ComposableNode launch description does not understand the nested structure in the YAML file, which causes the parameters to be (incorrectly) expanded to:

CompositionContainer received parameters:
name: test_node_otto.ros__parameters.some_int, type: integer
name: test_node_otto.ros__parameters.a_string, type: string

I think that there are two potential short-term workarounds (without requiring major changes in the way that the ComposableNode description works)

  1. Pass your existing yaml file in as a remapping argument in the launch description:
composable_node = ComposableNode(package='test', node_plugin='Test',
                                 remappings=[('__params', get_package_share_directory('test')+"/cfg/demo.yaml")])

This will then pass in parameters similar to the load call above.

  1. Use a new yaml file that doesn’t have any of the nesting:
some_int: 42
a_string: "Hello World"

And then pass that in as parameters to the ComposableNode description:

composable_node = ComposableNode(package='test', node_plugin='Test',
                                     parameters=[get_package_share_directory('test')+"/cfg/demo_no_nesting.yaml"])

The caveat on approach 1 is that any additional loose parameters passed via the parameters kwarg will always supersede what’s in the remappings argument, where in approach 2, the ordering in the list passed to parameters is important (later definitions will supersede earlier definitions).

So in the case of:

composable_node = ComposableNode(
        package='test',
        node_plugin='Test',
        parameters=[
            'some_file.yaml',  # {something: 'foo'}
            {'something': 'bar'},
            'some_other_file.yaml',  # {something: 'baz'}
        ])

The parameter something will be baz, but in the case of:

composable_node = ComposableNode(
        package='test',
        node_plugin='Test',
        parameters=[{'something': 'blah'}],
        remappings=[('__params', get_package_share_directory('test')+"/cfg/demo.yaml")])

The parameter something will be blah.