0
$\begingroup$

Rosanswers logo

Version: ROS2 Foxy

Platform: Ubuntu 20:04

Hello everyone,

I'm programmatically calling a launch file 'c' from a launch file 'b' from a launch file 'a' which is called in the terminal. In launch file 'b' I have two hard coded variables to calculate how many robots I want to spawn and where to spawn them. I want these hard coded variables to become arguments which are passed to launch file 'b' from launch file 'a'.

Without over complicating the question, I need to be able to perform calculations using them as typical python variables.

import os
from ament_index_python.packages import get_package_share_directory, get_package_prefix
from launch import LaunchDescription, LaunchContext
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch.substitutions import TextSubstitution, LaunchConfiguration,PythonExpression,PathJoinSubstitution

def gen_robot_list(number_of_robots, map_number):

#This function will calculate robot attributes using two variables
#This is the one condition I dont want to have to change.
_ = ''


def generate_launch_description():

#Process the URDF file
pkg_path = os.path.join(get_package_share_directory('my_bot'))
xacro_file = os.path.join(pkg_path,'description','robot.urdf.xacro')

map_number = LaunchConfiguration('map_number')
number_of_robots = LaunchConfiguration('number_of_robots')

#Below is where the argument variables will go (Replacing '2' and '7')
robots = gen_robot_list(2, 7)

# Create the list of spawn robots commands
spawn_robots_cmds = []

# Below is all neccessary for multi-robot control within ros name spaces and stuff
for robot in robots:
    print("#############"+str(robot))
    spawn_robots_cmds.append(
        IncludeLaunchDescription(
            PythonLaunchDescriptionSource(os.path.join(
                get_package_share_directory('my_bot'), 'launch', 'c.launch.py')),
            # Arguments to pass into the node which spawns the robot entity in gazebo
            launch_arguments={
                              'robot_urdf': xacro_file,
                              'x': TextSubstitution(text=str(robot['x_pose'])),
                              'y': TextSubstitution(text=str(robot['y_pose'])),
                              'z': TextSubstitution(text=str(robot['z_pose'])),
                              'robot_name': robot['name'],
                              'robot_name_prefix': robot['name']+'/',
                              'robot_namespace': robot['ns'],
                              'use_sim_time': 'true',
                              'rotation': TextSubstitution(text=str(robot['rotation'])),
                              }.items()
        )
    )

# Create the launch description and populate
ld = LaunchDescription()
# Creates a independent launch desc for each robot in list creating
# multiple robot state publishers and entity spawners
for spawn_robot_cmd in spawn_robots_cmds:
    ld.add_action(spawn_robot_cmd)

return ld

What have I tried so far:

I have managed to add simple LaunchArguments that I convert to LaunchConfiguration's. `

Declare a launch argument 'map_number'

map_number_arg = DeclareLaunchArgument(
    'map_number',
    default_value='1',
    description='Number of the map to be launched'
)

robot_number_arg = DeclareLaunchArgument(
    'robot_numbers',
    default_value='3',
    description='Number of robots to be launched'
)

# This Launch file handles the simulation of the environment (Gazebo)
start_world = IncludeLaunchDescription(
    PythonLaunchDescriptionSource(os.path.join(get_package_share_directory(package_name), 'launch', 'start_world.launch.py')),
    launch_arguments={
        'map_number': LaunchConfiguration('map_number'),
        'robot_number': TextSubstitution(text=str(LaunchConfiguration('robot_number')))
    }.items()
)`

These launch configuration can be passed to different launch files fine. But I cant access them as normal python variables I.E. I cant do LC=LaunchConfiguration('number_of_robots') then for i in range of(LC): or if LC==1:

I tried using Opaque Functions which allows the perform(context) function to work. This was the closest solution so far but I'm pretty sure they can only be used to launch nodes, not deal with calling other Launch files. I think this because every source code I have found using OpaqueFunction directly calls a Node, And when I try to call a Launch file with it. I get error: exception=AttributeError("'OpaqueFunction' object has no attribute 'get_launch_arguments'")

I tried using text substitutions which honestly sounded like they would fix everything but have a separate purpose that has nothing to do substituting LaunchConfigurations to strings

TO SUMMARISE:

I want to pass variables from one launch file to another, This must be done programmaticaly and I need to be able to use them as a pure python variable. I.E. will print(variable) print a string variable or will it print a LaunchConfugration object ID due to LaunchConfiguration's not being calculated during run time.

Been stuck on this for a couple months and I'm beginning to think this idea is not how ROS2 Launch files were designed to be used. So, if its truly not possible what would be a better alternative to the way I'm currently doing things.

Thanks for your time!


Originally posted by i1Cps on ROS Answers with karma: 3 on 2023-05-25

Post score: 0

$\endgroup$

1 Answer 1

0
$\begingroup$

Rosanswers logo

Hi,

As far as I know, the only way to change a LaunchConfiguration (e.g. argument value) to a raw Python type is through the opaque function. LaunchConfiguration's can be concatenated to others, or to string, that lead to a new LaunchConfiguration that can be passed to an included launch or to a node (params / remaps / arguments). But as you have seen, it cannot be used as a raw Python type which is necessary when using them in a loop.

You can find here an example of launch argument that is used in a loop through an opaque function. The loop calls another launch files in a given namespace, with some arguments. https://github.com/oKermorgant/anf_launch/blob/main/launch/spawn_all_launch.py

The anf_launch was created for a seminar on ROS 2 launch files and highlights most of the use cases.

Note that it relies on simple_launch (I am the author) to hide all the wrapping around OpaqueFunction.


Originally posted by Olivier Kermorgant with karma: 280 on 2023-05-26

This answer was ACCEPTED on the original site

Post score: 1


Original comments

Comment by i1Cps on 2023-06-12:
Thanks Olivier, simple_launch was exactly what i needed

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.