Hello!
I was watching this video: ROS2 Driver for Universal Robots - YouTube
and I agree, it’s quite strange how much you need to add an argument into a launch file.
So I was thinking it shouldn’t be so hard to at least simplify that down quite a bit…
I tried it in the UR ROS2 drivers ur_bringup launchfile, and just for context, this is how it looked in before I added my changes.
def launch_setup(context, *args, **kwargs):
# Initialize Arguments
ur_type = LaunchConfiguration("ur_type")
...
# creating all the other args and nodes_to_start, then using the LaunchConfiguration for the nodes_to_start.
...
return nodes_to_start
def generate_launch_description():
declared_arguments = []
# UR specific arguments
declared_arguments.append(
DeclareLaunchArgument(
"ur_type",
description="Type/series of used UR robot.",
choices=["ur3", "ur3e", "ur5", "ur5e", "ur10", "ur10e", "ur16e"],
)
)
....
return LaunchDescription(declared_arguments + [OpaqueFunction(function=launch_setup)])
So I created a class that extends LaunchConfiguration, so it can be used as a Substitution, with the created declaration and a getter for said declaration:
import collections.abc
from typing import List
from typing import Optional
from typing import Text
from launch.some_substitutions_type import SomeSubstitutionsType
from launch.substitutions import LaunchConfiguration
from launch.actions import DeclareLaunchArgument
class SimpleLaunchArgument(LaunchConfiguration):
def __init__(
self,
name: Text,
*,
default_value: Optional[SomeSubstitutionsType] = None,
description: Optional[Text] = None,
choices: List[Text] = None,
**kwargs
) -> None:
"""Declare the launch argument,"""
self.__declaration = DeclareLaunchArgument(name=name, default_value=default_value, description=description, choices=choices, **kwargs)
"""Then initialize it."""
super().__init__(variable_name=name, default=default_value)
@property
def declaration(self) -> DeclareLaunchArgument:
return self.__declaration
Basically the argument can be called as any LaunchConfiguration, and it’s declaration is automatically created and easily added.
So the end result would no longer need the OpaqueFunction, at least not in this case
def generate_launch_description():
# Initialize Arguments
ur_type = SimpleLaunchArgument(
"ur_type",
description="Type/series of used UR robot.",
choices=["ur3", "ur3e", "ur5", "ur5e", "ur10", "ur10e", "ur16e"]
)
# creating all the other args and nodes_to_start, then using the SimpleLaunchArgument as a LaunchConfiguration for the nodes_to_start.
launch_arg_declarations = [
ur_type.declaration,
.... # All the other args
return LaunchDescription(launch_arg_declarations + nodes_to_start)
I find this much easier to understand how the arguments are both being declared and used.
My suggestion would be to add this to the “launch.substitutions” library.
I was thinking of just doing a pull request of this to ros2/launch, but it said that I should bring it up here for discussion, so here ya go.
Any ideas, suggestions, objections?