def execute(self, context: LaunchContext) -> Optional[List[Action]]: """Execute the action.""" # resolve target container node name if is_a_subclass(self.__target_container, ComposableNodeContainer): self.__final_target_container_name = self.__target_container.node_name elif isinstance(self.__target_container, SomeSubstitutionsType_types_tuple): subs = normalize_to_list_of_substitutions(self.__target_container) self.__final_target_container_name = perform_substitutions( context, subs) else: self.__logger.error( 'target container is neither a ComposableNodeContainer nor a SubstitutionType' ) return # Create a client to load nodes in the target container. self.__rclpy_load_node_client = get_ros_node(context).create_client( composition_interfaces.srv.LoadNode, '{}/_container/load_node'.format( self.__final_target_container_name)) # Generate load requests before execute() exits to avoid race with context changing # due to scope change (e.g. if loading nodes from within a GroupAction). load_node_requests = [ get_composable_node_load_request(node_description, context) for node_description in self.__composable_node_descriptions ] context.add_completion_future( context.asyncio_loop.run_in_executor(None, self._load_in_sequence, load_node_requests, context))
def execute( self, context: LaunchContext ) -> Optional[List[Action]]: """Execute the action.""" # resolve target container node name if is_a_subclass(self.__target_container, ComposableNodeContainer): self.__final_target_container_name = self.__target_container.node_name elif isinstance(self.__target_container, SomeSubstitutionsType_types_tuple): subs = normalize_to_list_of_substitutions(self.__target_container) self.__final_target_container_name = perform_substitutions( context, subs) else: self.__logger.error( 'target container is neither a ComposableNodeContainer nor a SubstitutionType') return # Create a client to load nodes in the target container. self.__rclpy_load_node_client = get_ros_node(context).create_client( composition_interfaces.srv.LoadNode, '{}/_container/load_node'.format( self.__final_target_container_name ) ) context.add_completion_future( context.asyncio_loop.run_in_executor( None, self._load_in_sequence, self.__composable_node_descriptions, context ) )
def execute(self, context: LaunchContext) -> Optional[List[Action]]: """ Execute the action. Delegated to :meth:`launch.actions.ExecuteProcess.execute`. """ self._perform_substitutions(context) # Prepare the ros_specific_arguments list and add it to the context so that the # LocalSubstitution placeholders added to the the cmd can be expanded using the contents. ros_specific_arguments: Dict[str, Union[str, List[str]]] = {} if self.__node_name is not None: ros_specific_arguments['name'] = '__node:={}'.format(self.__expanded_node_name) if self.__expanded_node_namespace != '': ros_specific_arguments['ns'] = '__ns:={}'.format(self.__expanded_node_namespace) context.extend_locals({'ros_specific_arguments': ros_specific_arguments}) ret = super().execute(context) if self.is_node_name_fully_specified(): add_node_name(context, self.node_name) node_name_count = get_node_name_count(context, self.node_name) if node_name_count > 1: execute_process_logger = launch.logging.get_logger(self.name) execute_process_logger.warning( 'there are now at least {} nodes with the name {} created within this ' 'launch context'.format(node_name_count, self.node_name) ) return ret
def execute(self, context: LaunchContext) -> Optional[List[Action]]: """ Execute the action. Delegated to :meth:`launch.actions.ExecuteProcess.execute`. """ self._perform_substitutions(context) # Prepare the ros_specific_arguments list and add it to the context so that the # LocalSubstitution placeholders added to the the cmd can be expanded using the contents. ros_specific_arguments: Dict[str, Union[str, List[str]]] = {} if self.__node_name is not None: ros_specific_arguments['name'] = '__node:={}'.format( self.__expanded_node_name) if self.__expanded_node_namespace != '': ros_specific_arguments['ns'] = '__ns:={}'.format( self.__expanded_node_namespace) if self.__expanded_parameter_files is not None: ros_specific_arguments['params'] = [] param_arguments = cast(List[str], ros_specific_arguments['params']) for param_file_path in self.__expanded_parameter_files: param_arguments.append('__params:={}'.format(param_file_path)) if self.__expanded_remappings is not None: ros_specific_arguments['remaps'] = [] for remapping_from, remapping_to in self.__expanded_remappings: remap_arguments = cast(List[str], ros_specific_arguments['remaps']) remap_arguments.append('{}:={}'.format(remapping_from, remapping_to)) context.extend_locals( {'ros_specific_arguments': ros_specific_arguments}) return super().execute(context)
def execute(self, context: LaunchContext) -> Optional[List[Action]]: # TODO make sure this is done as late as possible context.register_event_handler(OnShutdown(on_shutdown=self._destroy)) # TODO make sure this is done as early as possible self._setup() if self.__ld_preload_action is not None: return [self.__ld_preload_action] return None
def execute(self, context: LaunchContext) -> Optional[List[Action]]: self.__perform_substitutions(context) # TODO make sure this is done as early as possible if not self._setup(): # Fail right away if tracing setup fails raise RuntimeError('tracing setup failed, see errors above') # TODO make sure this is done as late as possible context.register_event_handler(OnShutdown(on_shutdown=self._destroy)) return self.__ld_preload_actions
def add_node_name(context: LaunchContext, node_name: str) -> None: """ Add a node name to the context, indicating an occurrence of the node name. :param context: the context that keeps track of the node names :param node_name: the node name to keep track """ try: unique_node_names = context.locals.unique_ros_node_names except AttributeError: context.extend_globals({'unique_ros_node_names': defaultdict(int)}) unique_node_names = context.locals.unique_ros_node_names unique_node_names[node_name] += 1
def execute(self, context: LaunchContext): """Execute the action.""" eval_param_dict = evaluate_parameter_dict(context, self.__param_dict) global_param_list = context.launch_configurations.get( 'global_params', []) global_param_list.extend(eval_param_dict.items()) context.launch_configurations['global_params'] = global_param_list
def execute(self, context: LaunchContext): """Execute the action.""" src = perform_substitutions(context, self.__src) dst = perform_substitutions(context, self.__dst) global_remaps = context.launch_configurations.get('ros_remaps', []) global_remaps.append((src, dst)) context.launch_configurations['ros_remaps'] = global_remaps
def test_failing_command_rises(commands): """Test that a failing command raises.""" context = LaunchContext() command = Command(commands['failing']) with pytest.raises(SubstitutionFailure) as ex: command.perform(context) ex.match('executed command failed. Command: .*failing_command')
def test_reset(): xml_file = \ """\ <launch> <let name="foo" value="FOO"/> <let name="bar" value="BAR"/> <reset> <keep name="bar" value="$(var bar)"/> <keep name="baz" value="BAZ"/> </reset> </launch> """ # noqa: E501 xml_file = textwrap.dedent(xml_file) root_entity, parser = Parser.load(io.StringIO(xml_file)) ld = parser.parse_description(root_entity) assert isinstance(ld.entities[0], SetLaunchConfiguration) assert isinstance(ld.entities[1], SetLaunchConfiguration) assert isinstance(ld.entities[2], ResetLaunchConfigurations) lc = LaunchContext() assert len(lc.launch_configurations) == 0 ld.entities[0].visit(lc) ld.entities[1].visit(lc) assert len(lc.launch_configurations) == 2 assert 'foo' in lc.launch_configurations.keys() assert lc.launch_configurations['foo'] == 'FOO' assert 'bar' in lc.launch_configurations.keys() assert lc.launch_configurations['bar'] == 'BAR' ld.entities[2].visit(lc) assert 'foo' not in lc.launch_configurations.keys() assert 'bar' in lc.launch_configurations.keys() assert lc.launch_configurations['bar'] == 'BAR' assert 'baz' in lc.launch_configurations.keys() assert lc.launch_configurations['baz'] == 'BAZ'
def test_missing_command_raises(commands): """Test that a command that doesn't exist raises.""" context = LaunchContext() command = Command('ros2_launch_test_command_i_m_not_a_command') with pytest.raises(SubstitutionFailure) as ex: command.perform(context) ex.match('file not found:')
def test_group(): yaml_file = \ """\ launch: - let: name: 'foo' value: 'FOO' - let: name: 'bar' value: 'BAR' - group: scoped: True forwarding: False keep: - name: 'bar' value: $(var bar) - name: 'baz' value: 'BAZ' children: - let: name: 'var1' value: 'asd' - let: name: 'var2' value: 'asd' """ # noqa: E501 yaml_file = textwrap.dedent(yaml_file) root_entity, parser = Parser.load(io.StringIO(yaml_file)) ld = parser.parse_description(root_entity) assert isinstance(ld.entities[0], SetLaunchConfiguration) assert isinstance(ld.entities[1], SetLaunchConfiguration) assert isinstance(ld.entities[2], GroupAction) lc = LaunchContext() assert 0 == len(lc.launch_configurations) ld.entities[0].visit(lc) ld.entities[1].visit(lc) assert 2 == len(lc.launch_configurations) assert 'foo' in lc.launch_configurations.keys() assert 'FOO' == lc.launch_configurations['foo'] assert 'bar' in lc.launch_configurations.keys() assert 'BAR' == lc.launch_configurations['bar'] actions = ld.entities[2].execute(lc) assert 5 == len(actions) assert isinstance(actions[0], PushLaunchConfigurations) assert isinstance(actions[1], ResetLaunchConfigurations) assert isinstance(actions[2], SetLaunchConfiguration) assert isinstance(actions[3], SetLaunchConfiguration) assert isinstance(actions[4], PopLaunchConfigurations) actions[0].visit(lc) actions[1].visit(lc) assert 'foo' not in lc.launch_configurations.keys() assert 'bar' in lc.launch_configurations.keys() assert 'BAR' == lc.launch_configurations['bar'] assert 'baz' in lc.launch_configurations.keys() assert 'BAZ' == lc.launch_configurations['baz'] actions[2].visit(lc) actions[3].visit(lc) actions[4].visit(lc)
def execute(self, context: LaunchContext): """Execute the action.""" filename = perform_substitutions(context, self._input_file) global_param_list = context.launch_configurations.get( 'global_params', []) global_param_list.append(filename) context.launch_configurations['global_params'] = global_param_list
def _load_in_sequence(self, composable_node_descriptions: List[ComposableNode], context: LaunchContext) -> None: """ Load composable nodes sequentially. :param composable_node_descriptions: descriptions of composable nodes to be loaded :param context: current launch context """ next_composable_node_description = composable_node_descriptions[0] composable_node_descriptions = composable_node_descriptions[1:] self._load_node(next_composable_node_description, context) if len(composable_node_descriptions) > 0: context.add_completion_future( context.asyncio_loop.run_in_executor( None, self._load_in_sequence, composable_node_descriptions, context))
def _load_in_sequence(self, load_node_requests: List[ composition_interfaces.srv.LoadNode.Request], context: LaunchContext) -> None: """ Load composable nodes sequentially. :param composable_node_descriptions: descriptions of composable nodes to be loaded :param context: current launch context """ next_load_node_request = load_node_requests[0] load_node_requests = load_node_requests[1:] self._load_node(next_load_node_request, context) if len(load_node_requests) > 0: context.add_completion_future( context.asyncio_loop.run_in_executor(None, self._load_in_sequence, load_node_requests, context))
def test_command_with_stderr_raises(commands): """Test that a command that produces stderr raises.""" context = LaunchContext() command = Command(commands['with_stderr']) with pytest.raises(SubstitutionFailure) as ex: command.perform(context) ex.match( 'executed command showed stderr output. Command: .*command_with_stderr' r'[\w\W]*asd bsd')
def test_passthrough_properties(): name = 'name' cwd = 'cwd' env = {'a': '1'} exe = Executable(cmd=['test'], name=name, cwd=cwd, env=env) exe.prepare(LaunchContext(), None) assert exe.final_name.startswith(name) assert exe.final_cwd == cwd assert exe.final_env == env
def generate_launch_description(): map_yaml_file = os.getenv('TEST_MAP') world = os.getenv('TEST_WORLD') bt_navigator_xml = 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') params_file = os.path.join(bringup_dir, 'params', 'nav2_params.yaml') # Replace the `use_astar` setting on the params file param_substitutions = { 'planner_server.ros__parameters.GridBased.use_astar': 'False'} configured_params = RewrittenYaml( source_file=params_file, root_key='', param_rewrites=param_substitutions, convert_types=True) context = LaunchContext() new_yaml = configured_params.perform(context) return LaunchDescription([ SetEnvironmentVariable('RCUTILS_LOGGING_BUFFERED_STREAM', '1'), SetEnvironmentVariable('RCUTILS_LOGGING_USE_STDOUT', '1'), # Launch gazebo server for simulation ExecuteProcess( cmd=['gzserver', '-s', 'libgazebo_ros_init.so', '--minimal_comms', world], output='screen'), # TODO(orduno) Launch the robot state publisher instead # using a local copy of TB3 urdf file Node( package='tf2_ros', executable='static_transform_publisher', output='screen', arguments=['0', '0', '0', '0', '0', '0', 'base_footprint', 'base_link']), Node( package='tf2_ros', executable='static_transform_publisher', output='screen', arguments=['0', '0', '0', '0', '0', '0', 'base_link', 'base_scan']), IncludeLaunchDescription( PythonLaunchDescriptionSource( os.path.join(bringup_dir, 'launch', 'bringup_launch.py')), launch_arguments={'namespace': '', 'use_namespace': 'False', 'map': map_yaml_file, 'use_sim_time': 'True', 'params_file': new_yaml, 'bt_xml_file': bt_navigator_xml, 'autostart': 'True'}.items()), ])
def execute(self, context: LaunchContext) -> Optional[List[Action]]: """ Execute the action. Delegated to :meth:`launch.actions.ExecuteProcess.execute`. """ self._perform_substitutions(context) # Prepare the ros_specific_arguments list and add it to the context so that the # LocalSubstitution placeholders added to the the cmd can be expanded using the contents. ros_specific_arguments = [] # type: List[Text] if self.__node_name is not None: ros_specific_arguments.append('__node:={}'.format( self.__expanded_node_name)) if self.__node_namespace is not None: ros_specific_arguments.append('__ns:={}'.format( self.__expanded_node_namespace)) if self.__expanded_remappings is not None: for remapping_from, remapping_to in self.__remappings: ros_specific_arguments.append('{}:={}'.format( remapping_from, remapping_to)) context.extend_locals( {'ros_specific_arguments': ros_specific_arguments}) return super().execute(context)
def execute(self, context: LaunchContext): """Execute the action.""" pushed_namespace = perform_substitutions(context, self.namespace) previous_namespace = context.launch_configurations.get( 'ros_namespace', None) namespace = make_namespace_absolute( prefix_namespace(previous_namespace, pushed_namespace)) try: validate_namespace(namespace) except Exception: raise SubstitutionFailure( 'The resulting namespace is invalid:' " [previous_namespace='{}', pushed_namespace='{}']".format( previous_namespace, pushed_namespace)) context.launch_configurations['ros_namespace'] = namespace
def test_group(): xml_file = \ """\ <launch> <let name="foo" value="FOO"/> <let name="bar" value="BAR"/> <group scoped="True" forwarding="False"> <keep name="bar" value="$(var bar)"/> <keep name="baz" value="BAZ"/> <let name="var1" value="asd"/> <let name="var2" value="asd"/> </group> </launch> """ # noqa: E501 xml_file = textwrap.dedent(xml_file) root_entity, parser = Parser.load(io.StringIO(xml_file)) ld = parser.parse_description(root_entity) assert isinstance(ld.entities[0], SetLaunchConfiguration) assert isinstance(ld.entities[1], SetLaunchConfiguration) assert isinstance(ld.entities[2], GroupAction) lc = LaunchContext() assert 0 == len(lc.launch_configurations) ld.entities[0].visit(lc) ld.entities[1].visit(lc) assert 2 == len(lc.launch_configurations) assert 'foo' in lc.launch_configurations.keys() assert 'FOO' == lc.launch_configurations['foo'] assert 'bar' in lc.launch_configurations.keys() assert 'BAR' == lc.launch_configurations['bar'] actions = ld.entities[2].execute(lc) assert 5 == len(actions) assert isinstance(actions[0], PushLaunchConfigurations) assert isinstance(actions[1], ResetLaunchConfigurations) assert isinstance(actions[2], SetLaunchConfiguration) assert isinstance(actions[3], SetLaunchConfiguration) assert isinstance(actions[4], PopLaunchConfigurations) actions[0].visit(lc) actions[1].visit(lc) assert 'foo' not in lc.launch_configurations.keys() assert 'bar' in lc.launch_configurations.keys() assert 'BAR' == lc.launch_configurations['bar'] assert 'baz' in lc.launch_configurations.keys() assert 'BAZ' == lc.launch_configurations['baz'] actions[2].visit(lc) actions[3].visit(lc) actions[4].visit(lc)
def execute(self, context: LaunchContext): """Execute the action.""" with open(str(self.__param_file.evaluate(context)), 'r') as f: eval_param_dict = yaml.safe_load(f)['/**']['ros__parameters'] vehicle_info_keys = { 'wheel_radius', 'wheel_width', 'wheel_base', 'wheel_tread', 'front_overhang', 'rear_overhang', 'left_overhang', 'right_overhang', 'vehicle_height' } if vehicle_info_keys <= eval_param_dict.keys(): eval_param_dict['ready_vehicle_info_param'] = True global_params = context.launch_configurations.get('ros_params', {}) global_params.update(eval_param_dict) context.launch_configurations['ros_params'] = global_params else: raise RuntimeError('vehicle info param file is invalid.')
def execute(self, context: LaunchContext): """Execute the action.""" pushed_namespace = perform_substitutions(context, self.namespace) previous_namespace = context.launch_configurations.get( 'ros_namespace', '') namespace = pushed_namespace if not pushed_namespace.startswith('/'): namespace = previous_namespace + '/' + pushed_namespace namespace = namespace.rstrip('/') if namespace != '': try: validate_namespace(namespace) except Exception: raise SubstitutionFailure( 'The resulting namespace is invalid:' " [previous_namespace='{}', pushed_namespace='{}']".format( previous_namespace, pushed_namespace)) context.launch_configurations['ros_namespace'] = namespace
def test_reset(): yaml_file = \ """\ launch: - let: name: 'foo' value: 'FOO' - let: name: 'bar' value: 'BAR' - reset: keep: - name: 'bar' value: $(var bar) - name: 'baz' value: 'BAZ' """ # noqa: E501 print('Load YAML') yaml_file = textwrap.dedent(yaml_file) print('Load Parser') root_entity, parser = Parser.load(io.StringIO(yaml_file)) print('Parse Description') ld = parser.parse_description(root_entity) assert isinstance(ld.entities[0], SetLaunchConfiguration) assert isinstance(ld.entities[1], SetLaunchConfiguration) assert isinstance(ld.entities[2], ResetLaunchConfigurations) lc = LaunchContext() assert len(lc.launch_configurations) == 0 ld.entities[0].visit(lc) ld.entities[1].visit(lc) assert len(lc.launch_configurations) == 2 assert 'foo' in lc.launch_configurations.keys() assert lc.launch_configurations['foo'] == 'FOO' assert 'bar' in lc.launch_configurations.keys() assert lc.launch_configurations['bar'] == 'BAR' ld.entities[2].visit(lc) assert 'foo' not in lc.launch_configurations.keys() assert 'bar' in lc.launch_configurations.keys() assert lc.launch_configurations['bar'] == 'BAR' assert 'baz' in lc.launch_configurations.keys() assert lc.launch_configurations['baz'] == 'BAZ'
def test_substituted_properties(): os.environ['EXECUTABLE_NAME'] = 'name' os.environ['EXECUTABLE_CWD'] = 'cwd' os.environ['EXECUTABLE_ENVVAR'] = 'var' os.environ['EXECUTABLE_ENVVAL'] = 'value' name = EnvironmentVariable('EXECUTABLE_NAME') cwd = EnvironmentVariable('EXECUTABLE_CWD') env = { EnvironmentVariable('EXECUTABLE_ENVVAR'): EnvironmentVariable('EXECUTABLE_ENVVAL') } exe = Executable(cmd=['test'], name=name, cwd=cwd, env=env) exe.prepare(LaunchContext(), None) assert exe.final_name.startswith('name') assert exe.final_cwd == 'cwd' assert exe.final_env == {'var': 'value'} del os.environ['EXECUTABLE_NAME'] del os.environ['EXECUTABLE_CWD'] del os.environ['EXECUTABLE_ENVVAR'] del os.environ['EXECUTABLE_ENVVAL']
else: raise RuntimeError('No launch file supplied') launch_arguments.extend(args.launch_arguments) parsed_launch_arguments = parse_launch_arguments(launch_arguments) launch_description = launch.LaunchDescription([ launch.actions.IncludeLaunchDescription( launch.launch_description_sources.AnyLaunchDescriptionSource(path), launch_arguments=parsed_launch_arguments, ), ]) walker = [] walker.append(launch_description) ros_specific_arguments: Dict[str, Union[str, List[str]]] = {} context = LaunchContext(argv=launch_arguments) context._set_asyncio_loop(asyncio.get_event_loop()) try: # * Here we mimic the run loop inside launch_service, # but without actually kicking off the processes. # * Traverse the sub entities by DFS. # * Shadow the stdout to avoid random print outputs. mystring = StringIO() sys.stdout = mystring while walker: entity = walker.pop() visit_future = entity.visit(context) if visit_future is not None: visit_future.reverse() walker.extend(visit_future)
default_value='127.0.0.1', description='ROBOT_IP'), DeclareLaunchArgument('port', default_value='12345', description='ROBOT_PORT'), DeclareLaunchArgument('mode', default_value='virtual', description='OPERATION MODE'), DeclareLaunchArgument('model', default_value='m1013', description='ROBOT_MODEL'), DeclareLaunchArgument('color', default_value='white', description='ROBOT_COLOR'), ] context = LaunchContext() def load_file(package_name, file_path): package_path = get_package_share_directory(package_name) absolute_file_path = os.path.join(package_path, file_path) try: with open(absolute_file_path, 'r') as file: return file.read() except EnvironmentError: # parent of IOError, OSError *and* WindowsError where available return None def load_yaml(package_name, file_path): package_path = get_package_share_directory(package_name)
def test_command_with_stderr_warn(commands): """Test `Command` substitution with `on_stderr='warn'`.""" context = LaunchContext() command = Command(commands['with_stderr'], on_stderr='warn') output = command.perform(context) assert output == ''
def test_command_with_stderr_capture(commands): """Test `Command` substitution with `on_stderr='capture'`.""" context = LaunchContext() command = Command(commands['with_stderr'], on_stderr='capture') output = command.perform(context) assert output == 'asd bsd\n'