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

Can I programmatically call a launch file with arguments that can be used as a variable for python operations

asked 2023-05-25 14:32:41 -0500

i1Cps gravatar image

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 ... (more)

edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
1

answered 2023-05-26 02:58:52 -0500

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_la...

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.

edit flag offensive delete link more

Comments

Thanks Olivier, simple_launch was exactly what i needed

i1Cps gravatar image i1Cps  ( 2023-06-12 16:18:42 -0500 )edit

Question Tools

1 follower

Stats

Asked: 2023-05-25 14:32:41 -0500

Seen: 133 times

Last updated: May 26 '23