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

ros2 concatenate string to launchargument

asked 2020-08-04 07:16:57 -0600

.zero gravatar image

updated 2020-08-06 09:53:17 -0600

Hello there,

I am trying to port an old melodic project to eloquent and was wondering on how to concatenate strings to an launch argument like so:

return LaunchDescription([
    DeclareLaunchArgument('id', default_value='75', description="an id"),
    DeclareLaunchArgument('target', default_value="robot_"+launch.substitutions.LaunchConfiguration('id')+"/target"),
    Node(
        package='wand_control',
        node_executable='wand_control',
        output='screen',
        node_name="wand_control",
        node_namespace="aq_"+launch.substitutions.LaunchConfiguration("id"),
        parameters=[{
            "target" : launch.substitutions.LaunchConfiguration('target')
        }]
    )
])

but there is an error on the line where I am trying to set the launch argument 'target':

must be str, not LaunchConfiguration

Is there a way to achieve that?

edit retag flag offensive close merge delete

4 Answers

Sort by ยป oldest newest most voted
2

answered 2020-08-04 13:25:16 -0600

lukicdarkoo gravatar image

You can replace the string concatenation with an array, e.g.:

import launch
from launch.actions import DeclareLaunchArgument, LogInfo
from launch.substitutions import LaunchConfiguration


def generate_launch_description():
    return launch.LaunchDescription([
        DeclareLaunchArgument('id', default_value='75', description='an id'),
        DeclareLaunchArgument('target', default_value=['robot_', LaunchConfiguration('id'), '/target']),
        LogInfo(msg=LaunchConfiguration('target'))
    ])
edit flag offensive delete link more

Comments

Thank you! But why does it work that way?

.zero gravatar image .zero  ( 2020-08-06 10:24:28 -0600 )edit
1

Maybe somebody with a better understanding may be more suitable for this question.

But, the default_valueparameter is an array ( https://github.com/ros2/launch/blob/d...) and each element in the array is resolved as a substitution ( https://github.com/ros2/launch/blob/d...). Therefore, it shows that the DeclareLaunchArgument accepts a list of substitutions (or strings that are converted to substitutions).

Very often, substitutions accept a list, like PathJoinSubstitution( https://github.com/ros2/launch/blob/d...) and later it gets concatenated (https://github.com/ros2/launch/blob/d...)

lukicdarkoo gravatar image lukicdarkoo  ( 2020-08-08 09:01:33 -0600 )edit
0

answered 2020-10-01 07:47:18 -0600

atb033 gravatar image

You can do the following:

import launch
from launch.actions import DeclareLaunchArgument, LogInfo
from launch.substitutions import LaunchConfiguration


def generate_launch_description():

ld = launch.LaunchDescription()
declare_id = DeclareLaunchArgument('id', default_value='75', description='an id')
target = ['robot_', LaunchConfiguration('id'), '/target']
loginfo = LogInfo(msg = target)

ld.add_action(declare_id)
ld.add_action(loginfo)

return(ld)
edit flag offensive delete link more
0

answered 2022-10-11 03:57:41 -0600

Fellfalla gravatar image

updated 2022-10-11 04:01:01 -0600

I did implement my own TextFormatting substitution class. It basically does str.format() after substituting launch variables.

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at

#   http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License. 

"""Module for the TextFormatting substitution."""

from typing import Text
from typing import Iterable

from launch.launch_context import LaunchContext
from launch.substitution import Substitution
from launch.utilities import normalize_to_list_of_substitutions
from launch.some_substitutions_type import SomeSubstitutionsType


class TextFormatting(Substitution):
    """Substitution that wraps a single string text."""

    def __init__(self, text: Text, substitutions: Iterable[SomeSubstitutionsType]) -> None:
        """Create a TextSubstitution."""
        super().__init__()

        if not isinstance(text, Text):
            raise TypeError(
                "TextSubstitution expected Text object got '{}' instead.".format(type(text))
            )

        self.__text = text
        self.__substitutions = normalize_to_list_of_substitutions(substitutions)

    @property
    def substitutions(self) -> Iterable[Substitution]:
        """Getter for variable_name."""
        return self.__substitutions

    @property
    def text(self) -> Text:
        """Getter for text."""
        return self.__text

    def describe(self) -> Text:
        """Return a description of this substitution as a string."""
        return "{}%({})".format(self.text, ', '.join([s.describe() for s in self.substitutions]))

    def perform(self, context: LaunchContext) -> Text:
        """Perform the substitution by retrieving the local variable."""
        performed_substitutions = [sub.perform(context) for sub in self.__substitutions]
        return self.text.format(*performed_substitutions)

Which can be utilized as follows

from .text_formatting import TextFormatting
# [....]
target = launch.substitutions.LaunchConfiguration('target')
concatenated = TextFormatting('prefix{}postfix', target)

or in your case

return LaunchDescription([
    DeclareLaunchArgument('id', default_value='75', description="an id"),

    Node(
        package='wand_control',
        node_executable='wand_control',
        output='screen',
        node_name="wand_control",
        node_namespace="aq_"+launch.substitutions.LaunchConfiguration("id"),
        parameters=[{
            "target" : TextFormatting('{}/target',launch.substitutions.LaunchConfiguration('id'))
        }]
    )
])
edit flag offensive delete link more
0

answered 2022-11-30 15:52:14 -0600

BlakeAnderson gravatar image

The best way I've found so far is to use the PythonExpression subsitution. Here I append the filetype suffix to a string.

world_name = LaunchConfiguration('world')
world_filename = PythonExpression(expression=["'", world_name, "'", " + '.world'"])

Fellfalla's solution is good too and I'd like to see it get PRed into the main repository.

edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2020-08-04 07:16:57 -0600

Seen: 2,002 times

Last updated: Nov 30 '22