def test_evaluate_condition_expression():
    """Test common use cases for evaluate_condition_expression()."""
    class MockLaunchContext:
        def perform_substitution(self, substitution):
            return substitution.perform(self)

    lc = MockLaunchContext()
    test_cases = [
        ('true', True),
        ('True', True),
        ('TRUE', True),
        ('1', True),
        ('false', False),
        ('False', False),
        ('FALSE', False),
        ('0', False),
    ]

    for string, expected in test_cases:
        assert evaluate_condition_expression(
            lc, [TextSubstitution(text=string)]) is expected

    with pytest.raises(InvalidConditionExpressionError):
        evaluate_condition_expression(lc, [TextSubstitution(text='')])

    with pytest.raises(InvalidConditionExpressionError):
        evaluate_condition_expression(lc, [TextSubstitution(text='typo')])
Пример #2
0
 def __init__(self, *, world, gui, mode):
     self.__gui = gui if isinstance(
         gui, Substitution) else TextSubstitution(text=str(gui))
     self.__mode = mode if isinstance(
         mode, Substitution) else TextSubstitution(text=mode)
     self.__world = world if isinstance(
         world, Substitution) else TextSubstitution(text=world)
Пример #3
0
def test_dictionary_with_dissimilar_array():
    orig = [{'foo': 1, 'fiz': [True, 2.0, 3]}]
    norm = normalize_parameters(orig)
    expected = ({'foo': 1, 'fiz': ('True', '2.0', '3')}, )
    assert evaluate_parameters(LaunchContext(), norm) == expected

    orig = [{'foo': 1, 'fiz': [True, 1, TextSubstitution(text='foo')]}]
    norm = normalize_parameters(orig)
    expected = ({'foo': 1, 'fiz': ('True', '1', 'foo')}, )
    assert evaluate_parameters(LaunchContext(), norm) == expected

    orig = [{'foo': 1, 'fiz': [TextSubstitution(text='foo'), True, 1]}]
    norm = normalize_parameters(orig)
    expected = ({'foo': 1, 'fiz': ('foo', 'True', '1')}, )
    assert evaluate_parameters(LaunchContext(), norm) == expected

    orig = [{'foo': 1, 'fiz': [True, 1, [TextSubstitution(text='foo')]]}]
    norm = normalize_parameters(orig)
    expected = ({'foo': 1, 'fiz': ('True', '1', 'foo')}, )
    assert evaluate_parameters(LaunchContext(), norm) == expected

    orig = [{'foo': 1, 'fiz': [[TextSubstitution(text='foo')], True, 1]}]
    norm = normalize_parameters(orig)
    expected = ({'foo': 1, 'fiz': ('foo', 'True', '1')}, )
    assert evaluate_parameters(LaunchContext(), norm) == expected
Пример #4
0
def test_if_condition():
    """Test UnlessCondition class."""
    class MockLaunchContext:

        def perform_substitution(self, substitution):
            return substitution.perform(self)

    lc = MockLaunchContext()
    test_cases = [
        ('true', True),
        ('True', True),
        ('TRUE', True),
        ('1', True),
        ('false', False),
        ('False', False),
        ('FALSE', False),
        ('0', False),
    ]

    for string, expected in test_cases:
        assert UnlessCondition([TextSubstitution(text=string)]).evaluate(lc) is not expected

    with pytest.raises(InvalidConditionExpressionError):
        UnlessCondition([TextSubstitution(text='')]).evaluate(lc)

    with pytest.raises(InvalidConditionExpressionError):
        UnlessCondition([TextSubstitution(text='typo')]).evaluate(lc)
Пример #5
0
    def _parse_cmdline(cls, cmd: Text,
                       parser: Parser) -> List[SomeSubstitutionsType]:
        """
        Parse text apt for command line execution.

        :param: cmd a space (' ') delimited command line arguments list.
           All found `TextSubstitution` items are split and added to the
           list again as a `TextSubstitution`.
        :return: a list of command line arguments.
        """
        result_args = []
        arg: List[SomeSubstitutionsType] = []

        def _append_arg():
            nonlocal arg
            result_args.append(arg)
            arg = []

        for sub in parser.parse_substitution(cmd):
            if isinstance(sub, TextSubstitution):
                tokens = shlex.split(sub.text)
                if not tokens:
                    # Sting with just spaces.
                    # Appending args allow splitting two substitutions
                    # separated by a space.
                    # e.g.: `$(subst1 asd) $(subst2 bsd)` will be two separate arguments.
                    _append_arg()
                    continue
                if sub.text[0].isspace():
                    # Needed for splitting from the previous argument
                    # e.g.: `$(find-exec bsd) asd`
                    # It splits `asd` from the path of `bsd` executable.
                    if len(arg) != 0:
                        _append_arg()
                arg.append(TextSubstitution(text=tokens[0]))
                if len(tokens) > 1:
                    # Needed to split the first argument when more than one token.
                    # e.g. `$(find-pkg-prefix csd)/asd bsd`
                    # will split `$(find-pkg-prefix csd)/asd` from `bsd`.
                    _append_arg()
                    arg.append(TextSubstitution(text=tokens[-1]))
                if len(tokens) > 2:
                    # If there are more than two tokens, just add all the middle tokens to
                    # `result_args`.
                    # e.g. `$(find-pkg-prefix csd)/asd bsd dsd xsd`
                    # 'bsd' 'dsd' will be added.
                    result_args.extend([TextSubstitution(text=x)]
                                       for x in tokens[1:-1])
                if sub.text[-1].isspace():
                    # Allows splitting from next argument.
                    # e.g. `exec $(find-some-file)`
                    # Will split `exec` argument from the result of `find-some-file` substitution.
                    _append_arg()
            else:
                arg.append(sub)
        if arg:
            result_args.append(arg)
        return result_args
Пример #6
0
def test_is_normalized_substitution():
    assert is_normalized_substitution([TextSubstitution(text='asd')])
    assert is_normalized_substitution(
        [TextSubstitution(text='asd'),
         TextSubstitution(text='bsd')])

    assert not is_normalized_substitution(TextSubstitution(text='asd'))
    assert not is_normalized_substitution(
        [TextSubstitution(text='asd'), 'bsd'])
    assert not is_normalized_substitution(['bsd'])
    assert not is_normalized_substitution('bsd')
def test_dictionary_with_substitution():
    orig = [{TextSubstitution(text='bar'): TextSubstitution(text='baz')}]
    norm = normalize_parameters(orig)
    expected = ({'bar': 'baz'}, )
    assert evaluate_parameters(LaunchContext(), norm) == expected

    # substitutions get yamlfied
    orig = [{TextSubstitution(text='false'): TextSubstitution(text='off')}]
    norm = normalize_parameters(orig)
    expected = ({'false': False}, )
    assert evaluate_parameters(LaunchContext(), norm) == expected
Пример #8
0
def generate_launch_description():
    sim_arg = DeclareLaunchArgument('sim', default_value='False')
    fake_walk_arg = DeclareLaunchArgument('fake_walk', default_value='False')
    sim_ns_arg = DeclareLaunchArgument(
        'sim_ns', default_value=TextSubstitution(text='/'))
    robot_type_arg = DeclareLaunchArgument(
        'robot_type', default_value=TextSubstitution(text='wolfgang'))

    return LaunchDescription([
        sim_arg, fake_walk_arg, sim_ns_arg, robot_type_arg,
        OpaqueFunction(function=launch_setup)
    ])
def test_append_environment_variable_execute():
    """Test the execute() of the AppendEnvironmentVariable class."""
    lc1 = LaunchContext()

    # Sets environment variable if it does not exist
    if 'NONEXISTENT_KEY' in os.environ:
        del os.environ['NONEXISTENT_KEY']
    assert os.environ.get('NONEXISTENT_KEY') is None
    AppendEnvironmentVariable('NONEXISTENT_KEY', 'value').visit(lc1)
    assert os.environ.get('NONEXISTENT_KEY') == 'value'
    # Same result if prepending is enabled
    del os.environ['NONEXISTENT_KEY']
    AppendEnvironmentVariable('NONEXISTENT_KEY', 'value', prepend=True).visit(lc1)
    assert os.environ.get('NONEXISTENT_KEY') == 'value'

    # Appends to environment variable if it does exist
    AppendEnvironmentVariable('NONEXISTENT_KEY', 'another value').visit(lc1)
    assert os.environ.get('NONEXISTENT_KEY') == 'value' + os.pathsep + 'another value'

    # Prepends to environment variable if it does exist and option is enabled
    AppendEnvironmentVariable('NONEXISTENT_KEY', 'some value', prepend=True).visit(lc1)
    assert os.environ.get('NONEXISTENT_KEY') == \
        'some value' + os.pathsep + 'value' + os.pathsep + 'another value'

    # Can use an optional separator
    AppendEnvironmentVariable('NONEXISTENT_KEY', 'other value', separator='|').visit(lc1)
    assert os.environ.get('NONEXISTENT_KEY') == \
        'some value' + os.pathsep + 'value' + os.pathsep + 'another value' + '|' + 'other value'

    # Appends/prepends with substitutions
    assert os.environ.get('ANOTHER_NONEXISTENT_KEY') is None
    AppendEnvironmentVariable(
        'ANOTHER_NONEXISTENT_KEY',
        EnvironmentVariable('NONEXISTENT_KEY'),
        prepend=TextSubstitution(text='false')).visit(lc1)
    assert os.environ.get('ANOTHER_NONEXISTENT_KEY') == \
        'some value' + os.pathsep + 'value' + os.pathsep + 'another value' + '|' + 'other value'

    os.environ['ANOTHER_NONEXISTENT_KEY'] = 'abc'
    os.environ['SOME_SEPARATOR'] = '//'
    AppendEnvironmentVariable(
        'ANOTHER_NONEXISTENT_KEY',
        TextSubstitution(text='def'),
        separator=EnvironmentVariable('SOME_SEPARATOR'),
        prepend=TextSubstitution(text='yes')).visit(lc1)
    assert os.environ.get('ANOTHER_NONEXISTENT_KEY') == 'def' + '//' + 'abc'

    # Cleanup environment variables
    del os.environ['NONEXISTENT_KEY']
    del os.environ['ANOTHER_NONEXISTENT_KEY']
    del os.environ['SOME_SEPARATOR']
Пример #10
0
def test_dictionary_with_substitution_list_value():
    orig = [{
        'foo': [TextSubstitution(text='fiz'),
                TextSubstitution(text='buz')]
    }]
    norm = normalize_parameters(orig)
    expected = ({'foo': 'fizbuz'}, )
    assert evaluate_parameters(LaunchContext(), norm) == expected

    orig = [{
        'foo': [[TextSubstitution(text='fiz')], [TextSubstitution(text='buz')]]
    }]
    norm = normalize_parameters(orig)
    expected = ({'foo': ('fiz', 'buz')}, )
    assert evaluate_parameters(LaunchContext(), norm) == expected
Пример #11
0
def test_is_substitution():
    assert is_substitution(TextSubstitution(text='asd'))
    assert is_substitution([TextSubstitution(text='asd'), 'bsd'])
    assert is_substitution([
        'asd',
        TextSubstitution(text='bsd'),
    ])
    assert is_substitution([
        TextSubstitution(text='asd'),
        TextSubstitution(text='bsd'),
    ])
    assert not is_substitution([])
    assert not is_substitution('asd')
    assert not is_substitution(['asd', 'bsd'])
    assert not is_substitution(['asd', 'bsd'])
    assert not is_substitution(1)
Пример #12
0
def test_launch_configuration_not_equals():
    """Test LaunchConfigurationNotEquals class."""
    class MockLaunchContext:
        def perform_substitution(self, substitution):
            return substitution.perform(self)

        @property
        def launch_configurations(self):
            return {
                'foo': 'foo_value',
                'bar': 'bar_value',
                'empty': '',
            }

    lc = MockLaunchContext()
    test_cases = [
        ('foo', 'foo_value', False),
        ('bar', 'bar_value', False),
        ('bar', 'foo_value', True),
        ('bar', None, True),
        ('empty', '', False),
        ('empty', 'foo_value', True),
        ('empty', None, True),
        ('baz', None, False),
        ('baz', 'foo_value', True),
    ]

    for name, value, expected in test_cases:
        assert LaunchConfigurationNotEquals(
            name, [TextSubstitution(text=value)]
            if value is not None else None).evaluate(lc) is expected
Пример #13
0
    def test_action_substitutions(self) -> None:
        self.assertIsNone(os.environ.get('LD_PRELOAD'))
        tmpdir = tempfile.mkdtemp(
            prefix='TestTraceAction__test_action_substitutions')

        self.assertIsNone(os.environ.get('TestTraceAction__event_ust', None))
        os.environ['TestTraceAction__event_ust'] = 'ros2:*'
        self.assertIsNone(
            os.environ.get('TestTraceAction__context_field', None))
        os.environ['TestTraceAction__context_field'] = 'vpid'

        session_name_arg = DeclareLaunchArgument(
            'session-name',
            default_value='my-session-name',
            description='the session name',
        )
        action = Trace(
            session_name=LaunchConfiguration(session_name_arg.name),
            base_path=TextSubstitution(text=tmpdir),
            events_kernel=[],
            events_ust=[
                EnvironmentVariable(name='TestTraceAction__event_ust'),
                TextSubstitution(text='*'),
            ],
            context_fields={
                'kernel': [],
                'userspace': [
                    EnvironmentVariable(name='TestTraceAction__context_field'),
                    TextSubstitution(text='vtid'),
                ],
            },
        )
        self._assert_launch_no_errors([session_name_arg, action])
        self._check_trace_action(action, tmpdir)

        self.assertDictEqual(
            action.context_fields,
            {
                'kernel': [],
                'userspace': ['vpid', 'vtid'],
            },
        )

        shutil.rmtree(tmpdir)
        del os.environ['TestTraceAction__event_ust']
        del os.environ['TestTraceAction__context_field']
        del os.environ['LD_PRELOAD']
def test_launch_context_perform_substitution():
    """Test performing substitutions with LaunchContext class."""
    lc = LaunchContext()

    from launch.substitutions import TextSubstitution

    sub = TextSubstitution(text='foo')
    assert lc.perform_substitution(sub) == 'foo'
Пример #15
0
def test_mixed_substitutions():
    lc = LaunchContext()
    rule = (('foo', 'bar'), ['bar', TextSubstitution(text='baz')])
    output_rule = normalize_remap_rule(rule)
    assert isinstance(output_rule, tuple)
    assert len(output_rule) == 2
    assert 'foobar' == perform_substitutions(lc, output_rule[0])
    assert 'barbaz' == perform_substitutions(lc, output_rule[1])
def generate_launch_description():
    share_dir = get_package_share_directory('serial_driver')
    node_name = 'serial_bridge_node'

    params_declare = DeclareLaunchArgument(
        'params_file',
        default_value=os.path.join(share_dir, 'params', 'example.params.yaml'),
        description='File path to the ROS2 parameters file to use')

    bridge_node = LifecycleNode(
        package='serial_driver',
        executable='serial_bridge',
        name=node_name,
        namespace=TextSubstitution(text=''),
        parameters=[LaunchConfiguration('params_file')],
        output='screen',
    )

    configure_event_handler = RegisterEventHandler(
        event_handler=OnProcessStart(
            target_action=bridge_node,
            on_start=[
                EmitEvent(event=ChangeState(
                    lifecycle_node_matcher=matches_action(bridge_node),
                    transition_id=Transition.TRANSITION_CONFIGURE,
                ), ),
            ],
        ))

    activate_event_handler = RegisterEventHandler(
        event_handler=OnStateTransition(
            target_lifecycle_node=bridge_node,
            start_state='configuring',
            goal_state='inactive',
            entities=[
                EmitEvent(event=ChangeState(
                    lifecycle_node_matcher=matches_action(bridge_node),
                    transition_id=Transition.TRANSITION_ACTIVATE,
                ), ),
            ],
        ))

    shutdown_event_handler = RegisterEventHandler(event_handler=OnShutdown(
        on_shutdown=[
            EmitEvent(event=ChangeState(
                lifecycle_node_matcher=matches_node_name(node_name),
                transition_id=Transition.TRANSITION_ACTIVE_SHUTDOWN,
            ))
        ]))

    return LaunchDescription([
        params_declare,
        bridge_node,
        configure_event_handler,
        activate_event_handler,
        shutdown_event_handler,
    ])
Пример #17
0
def test_multiple_rules():
    lc = LaunchContext()
    rules = [('ping', 'pong'),
             (('baz', 'foo'), ['bar', TextSubstitution(text='baz')])]
    output_rules = list(normalize_remap_rules(rules))
    assert len(rules) == len(output_rules)
    assert 'ping' == perform_substitutions(lc, output_rules[0][0])
    assert 'pong' == perform_substitutions(lc, output_rules[0][1])
    assert 'bazfoo' == perform_substitutions(lc, output_rules[1][0])
    assert 'barbaz' == perform_substitutions(lc, output_rules[1][1])
Пример #18
0
def test_dictionary_with_mixed_substitutions_and_strings():
    orig = [{'foo': [TextSubstitution(text='fiz'), 'bar']}]
    norm = normalize_parameters(orig)
    expected = ({'foo': 'fizbar'}, )
    assert evaluate_parameters(LaunchContext(), norm) == expected

    orig = [{'foo': [[TextSubstitution(text='fiz')], 'bar']}]
    norm = normalize_parameters(orig)
    expected = ({'foo': ('fiz', 'bar')}, )
    assert evaluate_parameters(LaunchContext(), norm) == expected

    orig = [{'foo': ['bar', TextSubstitution(text='fiz')]}]
    norm = normalize_parameters(orig)
    expected = ({'foo': 'barfiz'}, )
    assert evaluate_parameters(LaunchContext(), norm) == expected

    orig = [{'foo': ['bar', [TextSubstitution(text='fiz')]]}]
    norm = normalize_parameters(orig)
    expected = ({'foo': ('bar', 'fiz')}, )
    assert evaluate_parameters(LaunchContext(), norm) == expected
Пример #19
0
def get_set_parameter_test_parameters():
    return [
        pytest.param(
            [('my_param', '2')],  # to set
            {'my_param': '2'},  # expected
            id='One param'),
        pytest.param([('my_param', '2'), ('another_param', '2'),
                      ('my_param', '3')], {
                          'my_param': '3',
                          'another_param': '2'
                      },
                     id='Two params, overriding one'),
        pytest.param([(TextSubstitution(text='my_param'),
                       TextSubstitution(text='my_value'))],
                     {'my_param': 'my_value'},
                     id='Substitution types'),
        pytest.param([((TextSubstitution(text='my_param'), ),
                       (TextSubstitution(text='my_value'), ))],
                     {'my_param': 'my_value'},
                     id='Tuple of substitution types'),
        pytest.param([([TextSubstitution(text='my_param')
                        ], [TextSubstitution(text='my_value')])],
                     {'my_param': 'my_value'},
                     id='List of substitution types'),
        pytest.param([('my_param', ParameterValue('my_value'))],
                     {'my_param': 'my_value'},
                     id='ParameterValue type'),
    ]
def initialize_robots(context, *args, **kwargs):
    """initialize robots"""
    base_frame = LaunchConfiguration('base_frame').perform(context)
    robots_file = LaunchConfiguration('robots_file').perform(context)
    spawner_dir = get_package_share_directory("robot_spawner_pkg")

    with open(robots_file, 'r') as stream:
        robots = yaml.safe_load(stream)

    nav_bringup_cmds = []
    for robot in robots:
        nav_bringup_cmds.append(
            IncludeLaunchDescription(
                PythonLaunchDescriptionSource(
                    os.path.join(spawner_dir, "single_real_robot.launch.py")),
                launch_arguments={
                    'x_pose': TextSubstitution(text=str(robot['x_pose'])),
                    'y_pose': TextSubstitution(text=str(robot['y_pose'])),
                    'z_pose': TextSubstitution(text=str(robot['z_pose'])),
                    'robot_name': TextSubstitution(text=str(robot['name'])),
                    'yaw_pose': TextSubstitution(text=str(robot['yaw_pose'])),
                    'base_frame': TextSubstitution(text=base_frame),
                    # 'turtlebot_type': TextSubstitution(text='burger')
                }.items()))
    return nav_bringup_cmds
Пример #21
0
def test_parameter_value_description():
    lc = MockContext()

    param = ParameterValue(value='asd')
    assert param.value == 'asd'
    assert param.value_type is None
    assert param.evaluate(lc) == 'asd'
    # After the first `evaluate` call, the following `.value` and `.evaluate()`
    # calls are calculated differently. Test them too.
    assert param.value == 'asd'
    assert param.evaluate(lc) == 'asd'

    param = ParameterValue(value='asd', value_type=str)
    assert param.value == 'asd'
    assert param.value_type is str
    assert param.evaluate(lc) == 'asd'
    assert param.value == 'asd'
    assert param.evaluate(lc) == 'asd'

    param = ParameterValue(value=TextSubstitution(text='1'))
    assert isinstance(param.value, list)
    assert len(param.value) == 1
    assert isinstance(param.value[0], TextSubstitution)
    assert param.evaluate(lc) == 1
    assert param.value == 1
    assert param.evaluate(lc) == 1

    param = ParameterValue(
        value=[
            '[',
            TextSubstitution(text='1, '),
            TextSubstitution(text='2, '),
            TextSubstitution(text='3, '),
            ']',
        ],
        value_type=List[int],
    )
    assert isinstance(param.value, list)
    assert param.evaluate(lc) == [1, 2, 3]
    assert param.value == [1, 2, 3]
    assert param.evaluate(lc) == [1, 2, 3]

    param = ParameterValue(value=TextSubstitution(text='[1, 2, 3]'), )
    assert isinstance(param.value, list)
    assert len(param.value) == 1
    assert isinstance(param.value[0], TextSubstitution)
    assert param.evaluate(lc) == [1, 2, 3]
    assert param.value == [1, 2, 3]
    assert param.evaluate(lc) == [1, 2, 3]

    with pytest.raises(TypeError):
        ParameterValue(value='1', value_type=int)

    param = ParameterValue(value=TextSubstitution(text='[1, asd, 3]'))
    with pytest.raises(ValueError):
        param.evaluate(lc)
def initialize_robots(context, *args, **kwargs):
    """initialize robots"""
    base_frame = LaunchConfiguration('base_frame').perform(context)
    robot_name_list = []
    robot_name_list_dir = os.path.join(
        get_package_share_directory('system_status'), 'local_ips.yaml')

    with open(robot_name_list_dir, 'r') as f:
        data = yaml.safe_load(f)
        robot_name_list = data[0]['local_ips']

    nav_bringup_cmds = []
    for robot_name in robot_name_list:
        robot_name = 'robot' + robot_name
        nav_bringup_cmds.append(
            IncludeLaunchDescription(
                PythonLaunchDescriptionSource(
                    [ThisLaunchFileDir(), "/single_real_robot.launch.py"]),
                launch_arguments={
                    'robot_name': TextSubstitution(text=robot_name),
                    'base_frame': TextSubstitution(text=base_frame),
                    # 'turtlebot_type': TextSubstitution(text='burger')
                }.items()))
    return nav_bringup_cmds
Пример #23
0
def test_unallowed_yaml_types_as_strings():
    # All the tests from test_unallowed_yaml_types_in_substitutions
    # but coerced to the proper type with ParameterValue
    orig = [{'foo': 1, 'fiz': ParameterValue(TextSubstitution(text="{'asd': 3}"), value_type=str)}]
    norm = normalize_parameters(orig)
    expected = ({'foo': 1, 'fiz': "{'asd': 3}"},)
    assert evaluate_parameters(LaunchContext(), norm) == expected

    orig = [{'foo': 1, 'fiz': ParameterValue(TextSubstitution(text='[1, 2.0, 3]'),
                                             value_type=str)}]
    norm = normalize_parameters(orig)
    evaluate_parameters(LaunchContext(), norm)
    expected = ({'foo': 1, 'fiz': '[1, 2.0, 3]'},)
    assert evaluate_parameters(LaunchContext(), norm) == expected

    orig = [{'foo': 1, 'fiz': ParameterValue(TextSubstitution(text='[[2, 3], [2, 3], [2, 3]]'),
                                             value_type=str)}]
    norm = normalize_parameters(orig)
    evaluate_parameters(LaunchContext(), norm)
    expected = ({'foo': 1, 'fiz': '[[2, 3], [2, 3], [2, 3]]'},)
    assert evaluate_parameters(LaunchContext(), norm) == expected

    orig = [{'foo': 1, 'fiz': ParameterValue(TextSubstitution(text='[]'), value_type=str)}]
    norm = normalize_parameters(orig)
    evaluate_parameters(LaunchContext(), norm)
    expected = ({'foo': 1, 'fiz': '[]'},)
    assert evaluate_parameters(LaunchContext(), norm) == expected

    orig = [{
        'foo': 1,
        'fiz': ParameterValue([
            [TextSubstitution(text="['asd', 'bsd']")],
            [TextSubstitution(text="['asd', 'csd']")]
        ], value_type=List[str])
    }]
    norm = normalize_parameters(orig)
    evaluate_parameters(LaunchContext(), norm)
    expected = ({'foo': 1, 'fiz': ["['asd', 'bsd']", "['asd', 'csd']"]},)
    assert evaluate_parameters(LaunchContext(), norm) == expected

    orig = [{'foo': 1,
             'fiz': ParameterValue(TextSubstitution(text='Text That : Cannot Be Parsed As : Yaml'),
                                   value_type=str)}]
    norm = normalize_parameters(orig)
    evaluate_parameters(LaunchContext(), norm)
    expected = ({'foo': 1, 'fiz': 'Text That : Cannot Be Parsed As : Yaml'},)
    assert evaluate_parameters(LaunchContext(), norm) == expected
Пример #24
0
def test_unallowed_yaml_types_in_substitutions():
    with pytest.raises(TypeError) as exc:
        orig = [{'foo': 1, 'fiz': TextSubstitution(text="{'asd': 3}")}]
        norm = normalize_parameters(orig)
        evaluate_parameters(LaunchContext(), norm)
    assert 'Allowed value types' in str(exc.value)
    assert 'dict' in str(exc.value)

    with pytest.raises(TypeError) as exc:
        orig = [{'foo': 1, 'fiz': TextSubstitution(text='[1, 2.0, 3]')}]
        norm = normalize_parameters(orig)
        evaluate_parameters(LaunchContext(), norm)
    assert 'Expected a non-empty sequence' in str(exc.value)

    with pytest.raises(TypeError) as exc:
        orig = [{'foo': 1, 'fiz': TextSubstitution(text='[[2, 3], [2, 3], [2, 3]]')}]
        norm = normalize_parameters(orig)
        evaluate_parameters(LaunchContext(), norm)
    assert 'Expected a non-empty sequence' in str(exc.value)

    with pytest.raises(TypeError) as exc:
        orig = [{'foo': 1, 'fiz': TextSubstitution(text='[]')}]
        norm = normalize_parameters(orig)
        evaluate_parameters(LaunchContext(), norm)
    assert 'Expected a non-empty sequence' in str(exc.value)

    with pytest.raises(TypeError) as exc:
        orig = [{
            'foo': 1,
            'fiz': [
                [TextSubstitution(text="['asd', 'bsd']")],
                [TextSubstitution(text="['asd', 'csd']")]
            ]
        }]
        norm = normalize_parameters(orig)
        evaluate_parameters(LaunchContext(), norm)
    assert 'Expected a non-empty sequence' in str(exc.value)

    with pytest.raises(TypeError) as exc:
        orig = [{'foo': 1, 'fiz': TextSubstitution(text='Text That : Cannot Be Parsed As : Yaml')}]
        norm = normalize_parameters(orig)
        evaluate_parameters(LaunchContext(), norm)
    assert 'Unable to parse' in str(exc.value)
def test_dictionary_with_dissimilar_array():
    with pytest.raises(TypeError) as exc:
        orig = [{'foo': 1, 'fiz': [True, 2.0, 3]}]
        norm = normalize_parameters(orig)
        evaluate_parameters(LaunchContext(), norm)
    assert 'Expected a non-empty' in str(exc.value)

    with pytest.raises(TypeError) as exc:
        orig = [{'foo': 1, 'fiz': [True, 1, TextSubstitution(text='foo')]}]
        norm = normalize_parameters(orig)
        evaluate_parameters(LaunchContext(), norm)
    assert 'Expected a non-empty' in str(exc.value)

    with pytest.raises(TypeError) as exc:
        orig = [{'foo': 1, 'fiz': [TextSubstitution(text='foo'), True, 1]}]
        norm = normalize_parameters(orig)
        evaluate_parameters(LaunchContext(), norm)
    assert 'Expected a non-empty' in str(exc.value)

    with pytest.raises(TypeError) as exc:
        orig = [{'foo': 1, 'fiz': [True, 1, [TextSubstitution(text='foo')]]}]
        norm = normalize_parameters(orig)
        evaluate_parameters(LaunchContext(), norm)
    assert 'Expected a non-empty' in str(exc.value)

    with pytest.raises(TypeError) as exc:
        orig = [{'foo': 1, 'fiz': [[TextSubstitution(text='foo')], True, 1]}]
        norm = normalize_parameters(orig)
        evaluate_parameters(LaunchContext(), norm)
    assert 'Expected a non-empty' in str(exc.value)

    with pytest.raises(TypeError) as exc:
        orig = [{
            'foo': [
                [TextSubstitution(text='True')],
                [TextSubstitution(text='2.0')],
                [TextSubstitution(text='3')],
            ]
        }]
        norm = normalize_parameters(orig)
        evaluate_parameters(LaunchContext(), norm)
    assert 'Expected a non-empty' in str(exc.value)
Пример #26
0
def get_set_parameter_test_parameters():
    return [
        pytest.param(
            [('my_param', '2')],  # to set
            [('my_param', '2')],  # expected
            id='One param'),
        pytest.param([(TextSubstitution(text='my_param'),
                       TextSubstitution(text='my_value'))],
                     [('my_param', 'my_value')],
                     id='Substitution types'),
        pytest.param([((TextSubstitution(text='my_param'), ),
                       (TextSubstitution(text='my_value'), ))],
                     [('my_param', 'my_value')],
                     id='Tuple of substitution types'),
        pytest.param([([TextSubstitution(text='my_param')
                        ], [TextSubstitution(text='my_value')])],
                     [('my_param', 'my_value')],
                     id='List of substitution types'),
        pytest.param([('my_param', ParameterValue('my_value'))],
                     [('my_param', 'my_value')],
                     id='ParameterValue type'),
    ]
Пример #27
0
def test_dictionary_with_substitution_list_name():
    orig = [{(TextSubstitution(text='bar'), TextSubstitution(text='foo')): 1}]
    norm = normalize_parameters(orig)
    expected = ({'barfoo': 1}, )
    assert evaluate_parameters(LaunchContext(), norm) == expected
Пример #28
0
def test_path_with_substitutions():
    orig = [(TextSubstitution(text='/foo'), TextSubstitution(text='/bar'))]
    norm = normalize_parameters(orig)
    expected = (pathlib.Path('/foo/bar'), )
    assert evaluate_parameters(LaunchContext(), norm) == expected
def generate_launch_description():
    map_yaml_file = os.getenv('TEST_MAP')
    world = os.getenv('TEST_WORLD')
    urdf = os.getenv('TEST_URDF')
    sdf = os.getenv('TEST_SDF')

    bt_xml_file = os.path.join(
        get_package_share_directory('nav2_bt_navigator'), 'behavior_trees',
        os.getenv('BT_NAVIGATOR_XML'))

    bringup_dir = get_package_share_directory('nav2_bringup')
    robot1_params_file = os.path.join(
        bringup_dir,  # noqa: F841
        'params/nav2_multirobot_params_1.yaml')
    robot2_params_file = os.path.join(
        bringup_dir,  # noqa: F841
        'params/nav2_multirobot_params_2.yaml')

    # Names and poses of the robots
    robots = [{
        'name': 'robot1',
        'x_pose': 0.0,
        'y_pose': 0.5,
        'z_pose': 0.01
    }, {
        'name': 'robot2',
        'x_pose': 0.0,
        'y_pose': -0.5,
        'z_pose': 0.01
    }]

    # Launch Gazebo server for simulation
    start_gazebo_cmd = ExecuteProcess(cmd=[
        'gzserver', '-s', 'libgazebo_ros_factory.so', '--minimal_comms', world
    ],
                                      output='screen')

    # Define commands for spawing the robots into Gazebo
    spawn_robots_cmds = []
    for robot in robots:
        spawn_robots_cmds.append(
            Node(package='nav2_gazebo_spawner',
                 executable='nav2_gazebo_spawner',
                 output='screen',
                 arguments=[
                     '--robot_name',
                     TextSubstitution(text=robot['name']), '--robot_namespace',
                     TextSubstitution(text=robot['name']), '--sdf',
                     TextSubstitution(text=sdf), '-x',
                     TextSubstitution(text=str(robot['x_pose'])), '-y',
                     TextSubstitution(text=str(robot['y_pose'])), '-z',
                     TextSubstitution(text=str(robot['z_pose']))
                 ]))

    # Define commands for launching the robot state publishers
    robot_state_pubs_cmds = []
    for robot in robots:
        robot_state_pubs_cmds.append(
            Node(package='robot_state_publisher',
                 executable='robot_state_publisher',
                 namespace=TextSubstitution(text=robot['name']),
                 output='screen',
                 parameters=[{
                     'use_sim_time': 'True'
                 }],
                 remappings=[('/tf', 'tf'), ('/tf_static', 'tf_static')],
                 arguments=[urdf]))

    # Define commands for launching the navigation instances
    nav_instances_cmds = []
    for robot in robots:
        params_file = eval(f"{robot['name']}_params_file")

        group = GroupAction([
            # Instances use the robot's name for namespace
            PushRosNamespace(robot['name']),
            IncludeLaunchDescription(PythonLaunchDescriptionSource(
                os.path.join(bringup_dir, 'launch', 'bringup_launch.py')),
                                     launch_arguments={
                                         'namespace': robot['name'],
                                         'map': map_yaml_file,
                                         'use_sim_time': 'True',
                                         'params_file': params_file,
                                         'bt_xml_file': bt_xml_file,
                                         'autostart': 'True',
                                         'use_remappings': 'True'
                                     }.items())
        ])
        nav_instances_cmds.append(group)

    ld = LaunchDescription()
    ld.add_action(
        SetEnvironmentVariable('RCUTILS_LOGGING_BUFFERED_STREAM', '1'), )
    ld.add_action(SetEnvironmentVariable('RCUTILS_LOGGING_USE_STDOUT', '1'), )
    ld.add_action(start_gazebo_cmd)
    for spawn_robot in spawn_robots_cmds:
        ld.add_action(spawn_robot)
    for state_pub in robot_state_pubs_cmds:
        ld.add_action(state_pub)
    for nav_instance in nav_instances_cmds:
        ld.add_action(nav_instance)

    return ld
def generate_launch_description():
    # Get the launch directory
    bringup_dir = get_package_share_directory('nav2_bringup')

    # Names and poses of the robots
    robots = [{
        'name': 'robot1',
        'x_pose': 0.0,
        'y_pose': 0.5,
        'z_pose': 0.01
    }, {
        'name': 'robot2',
        'x_pose': 0.0,
        'y_pose': -0.5,
        'z_pose': 0.01
    }]

    # Simulation settings
    world = LaunchConfiguration('world')
    simulator = LaunchConfiguration('simulator')

    # On this example all robots are launched with the same settings
    map_yaml_file = LaunchConfiguration('map')
    params_file = LaunchConfiguration('params_file')
    bt_xml_file = LaunchConfiguration('bt_xml_file')
    rviz_config_file = LaunchConfiguration('rviz_config')
    log_settings = LaunchConfiguration('log_settings', default='true')

    # Declare the launch arguments
    declare_world_cmd = DeclareLaunchArgument(
        'world',
        default_value=os.path.join(bringup_dir, 'worlds', 'world_only.model'),
        description='Full path to world file to load')

    declare_simulator_cmd = DeclareLaunchArgument(
        'simulator',
        default_value='gazebo',
        description='The simulator to use (gazebo or gzserver)')

    declare_map_yaml_cmd = DeclareLaunchArgument(
        'map',
        default_value=os.path.join(bringup_dir, 'maps',
                                   'turtlebot3_world.yaml'),
        description='Full path to map file to load')

    declare_params_file_cmd = DeclareLaunchArgument(
        'params_file',
        default_value=os.path.join(bringup_dir, 'params', 'nav2_params.yaml'),
        description=
        'Full path to the ROS2 parameters file to use for all launched nodes')

    declare_bt_xml_cmd = DeclareLaunchArgument(
        'bt_xml_file',
        default_value=os.path.join(
            get_package_share_directory('nav2_bt_navigator'), 'behavior_trees',
            'navigate_w_replanning_and_recovery.xml'),
        description='Full path to the behavior tree xml file to use')

    declare_rviz_config_file_cmd = DeclareLaunchArgument(
        'rviz_config',
        default_value=os.path.join(bringup_dir, 'rviz',
                                   'nav2_namespaced_view.rviz'),
        description='Full path to the RVIZ config file to use')

    # Start Gazebo with plugin providing the robot spawing service
    start_gazebo_cmd = ExecuteProcess(
        cmd=[simulator, '--verbose', '-s', 'libgazebo_ros_factory.so', world],
        output='screen')

    # Define commands for spawing the robots into Gazebo
    spawn_robots_cmds = []
    for robot in robots:
        spawn_robots_cmds.append(
            IncludeLaunchDescription(
                PythonLaunchDescriptionSource(
                    os.path.join(bringup_dir, 'launch',
                                 'spawn_robot_launch.py')),
                launch_arguments={
                    'x_pose': TextSubstitution(text=str(robot['x_pose'])),
                    'y_pose': TextSubstitution(text=str(robot['y_pose'])),
                    'z_pose': TextSubstitution(text=str(robot['z_pose'])),
                    'robot_name': robot['name'],
                    'turtlebot_type': TextSubstitution(text='waffle')
                }.items()))

    # Define commands for launching the navigation instances
    nav_instances_cmds = []
    for robot in robots:
        namespaced_rviz_config_file = ReplaceString(
            source_file=rviz_config_file,
            replacements={'<robot_namespace>': ('/' + robot['name'])})

        group = GroupAction([
            # TODO(orduno)
            # Each `action.Node` within the `localization` and `navigation` launch
            # files has two versions, one with the required remaps and another without.
            # The `use_remappings` flag specifies which runs.
            # A better mechanism would be to have a PushNodeRemapping() action:
            # https://github.com/ros2/launch_ros/issues/56
            # For more on why we're remapping topics, see the note below

            # PushNodeRemapping(remappings)

            # Instances use the robot's name for namespace
            PushRosNamespace(robot['name']),
            IncludeLaunchDescription(
                PythonLaunchDescriptionSource(
                    os.path.join(bringup_dir, 'launch',
                                 'nav2_tb3_simulation_launch.py')),
                launch_arguments={
                    # TODO(orduno) might not be necessary to pass the robot name
                    'namespace': robot['name'],
                    'map_yaml_file': map_yaml_file,
                    'use_sim_time': 'True',
                    'params_file': params_file,
                    'bt_xml_file': bt_xml_file,
                    'autostart': 'False',
                    'use_remappings': 'True',
                    'rviz_config_file': namespaced_rviz_config_file,
                    'use_simulator': 'False'
                }.items()),
            LogInfo(condition=IfCondition(log_settings),
                    msg=['Launching ', robot['name']]),
            LogInfo(condition=IfCondition(log_settings),
                    msg=[robot['name'], ' map yaml: ', map_yaml_file]),
            LogInfo(condition=IfCondition(log_settings),
                    msg=[robot['name'], ' params yaml: ', params_file]),
            LogInfo(condition=IfCondition(log_settings),
                    msg=[robot['name'], ' behavior tree xml: ', bt_xml_file]),
            LogInfo(condition=IfCondition(log_settings),
                    msg=[
                        robot['name'], ' rviz config file: ',
                        namespaced_rviz_config_file
                    ])
        ])

        nav_instances_cmds.append(group)

    # A note on the `remappings` variable defined above and the fact it's passed as a node arg.
    # A few topics have fully qualified names (have a leading '/'), these need to be remapped
    # to relative ones so the node's namespace can be prepended.
    # In case of the transforms (tf), currently, there doesn't seem to be a better alternative
    # for multi-robot transforms:
    # https://github.com/ros/geometry2/issues/32
    # https://github.com/ros/robot_state_publisher/pull/30

    # Create the launch description and populate
    ld = LaunchDescription()

    # Declare the launch options
    ld.add_action(declare_simulator_cmd)
    ld.add_action(declare_world_cmd)
    ld.add_action(declare_map_yaml_cmd)
    ld.add_action(declare_params_file_cmd)
    ld.add_action(declare_bt_xml_cmd)
    ld.add_action(declare_rviz_config_file_cmd)

    # Add the actions to start gazebo, robots and simulations
    ld.add_action(start_gazebo_cmd)

    for spawn_robot_cmd in spawn_robots_cmds:
        ld.add_action(spawn_robot_cmd)

    for simulation_instance_cmd in nav_instances_cmds:
        ld.add_action(simulation_instance_cmd)

    return ld