ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
1

[ROS2] How do you load a yaml config file to a Composable Node?

asked 2020-04-03 10:16:25 -0500

Andreas Ziegler gravatar image

updated 2021-01-25 19:31:13 -0500

M@t gravatar image

I would like to pass parameters to a composable node from a yaml config file. I searched on the web I saw that there were multiple bugs. Unfortunately I couldn't find any current example.

I would be glad if someone could let me know, where I can find something. I would like to know:

  • the correct format in the yaml file
  • how to load it with parameters=[get_package_share_directory('my_package')+"/config/my_config.yaml"]

Edit: @johnconn: Unfortunately this doesn't work for me. Could it be that the config has to look different when I use a ComposableNode instead of a normal Node?

My launch file is now

import os.path
import launch
from launch_ros.actions import ComposableNodeContainer
from launch_ros.descriptions import ComposableNode
from launch.substitutions import LaunchConfiguration
from ament_index_python import get_package_share_directory


def generate_launch_description():
    """Generate launch description with multiple components."""

    # config the serial number and base frame id of each camera
    d435_base_frame_id = LaunchConfiguration('base_frame_id', default='d435_link')
    d435_serial_no = LaunchConfiguration('serial_no', default='825312073597')

    d435i_base_frame_id = LaunchConfiguration('base_frame_id', default='d435i_link')
    d435i_serial_no = LaunchConfiguration('serial_no', default='845112070204')

    print(get_package_share_directory('safety-field-intrusion-detector-ros')+"/config/d435.yaml")

    container = ComposableNodeContainer(
            node_name='safety_field_intrusion_detection',
            node_namespace='',
            package='rclcpp_components',
            node_executable='component_container',
            composable_node_descriptions=[
                ComposableNode(
                    package='realsense_ros',
                    node_plugin='realsense::RealSenseNodeFactory',
                    node_name='d435',
                    #node_name='realsense',
                    node_namespace='realsense',
                    parameters=[
                        #get_package_share_directory('safety-field-intrusion-detector-ros')+"/config/d435.yaml"
                        os.path.join(get_package_share_directory('safety-field-intrusion-detector-ros'), 'config', 'd435.yaml')
                        #{'serial_no': d435_serial_no,
                        # 'base_frame_id': d435_base_frame_id}
                    ]
                ),
                ComposableNode(
                    package='realsense_ros',
                    node_plugin='realsense::RealSenseNodeFactory',
                    node_name='d435i',
                    #node_name='realsense',
                    node_namespace='realsense',
                    parameters=[
                        #get_package_share_directory('safety-field-intrusion-detector-ros')+"/config/d435i.yaml"
                        os.path.join(get_package_share_directory('safety-field-intrusion-detector-ros'), 'config', 'd435i.yaml')
                        #{'serial_no': d435i_serial_no,
                        # 'base_frame_id': d435i_base_frame_id}
                    ]
                ),
                ComposableNode(
                    package='safety-field-intrusion-detector-ros',
                    node_plugin='SafetyFieldIntrusionDetectorBaseNode',
                    node_name='safety_field_intrusion_detector',
                    parameters=[
                        get_package_share_directory('safety-field-intrusion-detector-ros')+"/config/params.yaml"
                ])
            ],
            output='screen',
    )

    return launch.LaunchDescription([container])

and my config files

realsense/d435:
  ros__parameters:
    serial_no: 825312073597 # d435
    base_frame_id: d435_link
    align_depth: true
    enable_pointcloud: false
    dense_pointcloud: false
    color0:
      enabled: true
      resolution: [640,480]
      fps: 30
    depth0:
      enabled: true
      resolution: [640,480]
      fps: 30
    infra1:
      enabled: false
      resolution: [640,480]
      fps: 30
    infra2:
      enabled: false
      resolution: [640,480]
      fps: 30

and

realsense/d435i:
  ros__parameters:
    serial_no: 845112070204 # d435i
    base_frame_id: d435i_link
    align_depth: true
    enable_pointcloud: false
    dense_pointcloud: false
    color0:
      enabled: true
      resolution: [640,480]
      fps: 30
    depth0:
      enabled: true
      resolution: [640,480]
      fps: 30
    infra1:
      enabled: false
      resolution: [640,480]
      fps: 30
    infra2:
      enabled: false
      resolution: [640,480]
      fps: 30
    accel0:
      enabled: true
    gyro0:
      enabled: true

when I launch it, I get the following errors:

ros2 launch safety-field-intrusion-detector-ros safety_field_detector.launch.py
[INFO] [launch]: All log files can be found below /home/mtr/.ros/log/2020-04-06-08-25-32-985607-UP2-board-6505
[INFO] [launch]: Default logging verbosity is set to INFO
/home/mtr/ros/safety_field_detector_ws/install/safety-field-intrusion-detector-ros/share/safety-field-intrusion-detector-ros/config/d435.yaml
[INFO] [component_container-1]: process started with pid [6516]
[ERROR] [launch_ros.actions.load_composable_nodes]: Failed to load node 'd435' of type 'realsense::RealSenseNodeFactory' in container '/safety_field_intrusion_detection': Component constructor threw an exception
[INFO] [launch_ros.actions.load_composable_nodes]: Loaded node '' in container '/safety_field_intrusion_detection'
[component_container-1] [WARN] [rcl]: Namespace not remapped to a fully qualified name (found: realsense)
[component_container-1] [ERROR] [safety_field_intrusion_detection]: Component constructor threw an exception
[component_container-1] [WARN] [rcl]: Namespace not remapped to a fully qualified name (found: realsense)
[ERROR] [launch_ros.actions.load_composable_nodes]: Failed to load node 'd435i' of type 'realsense ...
(more)
edit retag flag offensive close merge delete

Comments

@Andreas Ziegler: please only post answers when actually answering a question.

ROS Answers is an instance of AskBot, which is similar to Stack Overflow, and works best with a 1-to-1 ratio of answers and questions.

To interact with answerers, post comments under their answers, or edit your own question text.

I've merged your non-answer with your question for you, but please keep it in mind for next time.

gvdhoorn gravatar image gvdhoorn  ( 2020-04-07 02:51:53 -0500 )edit

@gvdhoorn: Thanks for fixing my mess. My intention was to add another comment as I'm used to from GitHub or StackOverflow rather than answering my question but the only button I found was the "Answer button".

Andreas Ziegler gravatar image Andreas Ziegler  ( 2020-04-07 04:00:40 -0500 )edit

You should have a add a comment button/link under the answer you want to respond to.

gvdhoorn gravatar image gvdhoorn  ( 2020-04-07 04:01:57 -0500 )edit

I haven't gone beyond the demos for composable nodes yet, I'm not sure if there is a difference.

johnconn gravatar image johnconn  ( 2020-04-07 09:53:29 -0500 )edit

2 Answers

Sort by ยป oldest newest most voted
5

answered 2021-01-25 19:25:02 -0500

M@t gravatar image

updated 2021-01-25 19:27:24 -0500

As of ROS2 Foxy, there are still ongoing issues/discussions regarding this. See the following Github threads if you're interested:

TL;DR: Composable Nodes are NOT treated the same as ordinary Nodes in ROS2. The only code I've found to work is the following:

import os
import yaml
import launch
from launch_ros.actions import Node
from ament_index_python.packages import get_package_share_directory
from launch_ros.actions import ComposableNodeContainer
from launch_ros.descriptions import ComposableNode

def generate_launch_description():    

    # Get the filepath to your config file
    configFilepath = os.path.join(
        get_package_share_directory("my_package_name"), 
        'my_params.yaml'
    )                       

    # Load the parameters specific to your ComposableNode
    with open(configFilepath, 'r') as file:
        configParams = yaml.safe_load(file)['my_node_name']['ros__parameters']   

    # Create your ComposableNode
    container = ComposableNodeContainer(
        name='my_container_name',
        namespace='',
        package='rclcpp_components',
        executable='component_executable',         # This name must match your CMakelist file
        composable_node_descriptions=[
            ComposableNode(
                package='my_package_name',
                plugin='my_namespace::my_node_class', 
                name='my_node_name',
                parameters=[configParams]
            )
        ],
        output='screen',
    )

    return launch.LaunchDescription([container])

It is honestly a real pain that they're not treated the same way, but that's hopefully something that will change in future ROS2 distros.

Also note that there are a lot of edits you need to make to your CMakelists file to get your node to even compile in a way that allows the executable to be composed. But for that you should look at the composition demo code.

edit flag offensive delete link more
0

answered 2020-04-03 16:18:36 -0500

johnconn gravatar image

updated 2020-04-07 09:54:40 -0500

Edit: The code below works for standard nodes, haven't tested trying to use composable nodes which the op isn't able to get working

the launch file:

back_camera = Node(
    package='realsense_node',
    node_executable='realsense_node',
    node_name='d435',
    node_namespace='back',
    output='screen',
    respawn=False,
    parameters=[
        os.path.join(get_package_share_directory('realsense_examples'),'config','example.yaml'),
        {
        'json_file_path': full_json_file_path, 
        }]
    )

the yaml file:

back/d435:
    ros__parameters:
        log_level: 'info'

        serial_no: 933322071235 # d435
        align_depth: true
        enable_pointcloud: true
        dense_pointcloud: true
        color0:
          enabled: true
          resolution: [640,480]
          fps: 15 
        depth0:
          enabled: true
          resolution: [640,480]
          fps: 15 
        infra1:
          enabled: true
          resolution: [640,480]
          fps: 15 
        infra2:
          enabled: true
          resolution: [640,480]
          fps: 15

for eloquent

edit flag offensive delete link more

Question Tools

4 followers

Stats

Asked: 2020-04-03 10:16:25 -0500

Seen: 4,272 times

Last updated: Jan 25 '21