ros2 / launch

Tools for launching multiple processes and for writing tests involving multiple processes.
Apache License 2.0
126 stars 141 forks source link

How do I access the runtime/future value of a LaunchConfiguration (or any LaunchDescriptionEntity subclass) within an OpaqueFunction? #599

Closed alikureishy closed 2 years ago

alikureishy commented 2 years ago

Bug report

Required Info:

Steps to reproduce issue

I'm trying to add custom functionality into my launch file(s) that depends on the runtime value of a/few LaunchConfiguration object(s). For example, a yaml_file_path argument:

def generate_launch_description():
   yaml_file_path = LaunchConfiguration('yaml_file_path')
   yaml_file_path_arg = DeclareLaunchArgument('yaml_file_path')

   ...

The aforementioned argument (yaml_file_path) will provide me the path to a yaml file containing a list of entities that I need to then iterate over and "process" in some application-specific way, within the launch code itself. I am not trying to provide these as parameters to a node -- that is not what this question is about.

Since everything in these launch files is essentially an asyncio future, I'm trying to understand how to specify such custom processing within the launch file itself. In my case, this custom processing includes adding an IncludeLaunchDescription instance for each module entry in the yaml file, into a list called module_includes, before returning it from the generate_launch_description() api. For example, the yaml file will contain:

#
# Note, again, that this is *not* for setting node parameters
#
module_a:
   prefix: "x/y/z"
   ...
module_b:
   prefix: "a/b/c"
   ...

The processing I'm trying to implement, is:

def generate_includes(context: LaunchContext, yaml_file_path: str) -> List[LaunchDescriptionEntity]:
   # TODO: Parse yaml file into dict
   settings: Dict[str, Any] = parse_yaml_file(yaml_file_path)

   module_includes: List[IncludeLaunchDescription] = []
   for (key,value) in settings.items():
      module_includes.append(
         IncludeLaunchDescription(
            PythonLaunchDescriptionSource(
               PathJoinSubstitution([settings[key]['prefix'], "module.launch.py"])
            ),
            launch_arguments=[...]
         )
      ),
      module_includes.append(
         LogInfo(msg=(["\tIncluding file: ", PathJoinSubstitution([settings[key]['prefix'], "module.launch.py"])))
      )
   return module_includes

Based on reading the code, I understand I need to define and return an OpaqueFunction within my generate_launch_description() method, as below:

def generate_launch_description():
   yaml_file_path = LaunchConfiguration('yaml_file_path')
   yaml_file_path_arg = DeclareLaunchArgument('yaml_file_path')

   ...
   variable_modules_includer = OpaqueFunction(generate_includes, ...<???>...)

   return [
       yaml_file_path_arg,
       variable_modules_includer,
   ]

... but, I'm not being able to understand:

Some sample code, wherever applicable, would be greatly appreciated.

alikureishy commented 2 years ago

Realized this should be on answers.ros.org. For posterity's sake, here's the link to that question. Closing this issue here.