런치 파일의 기본 개념

ROS2에서 런치 파일은 여러 노드를 동시에 실행하고 관리하기 위한 중요한 도구이다. 런치 파일을 사용하면 시스템의 복잡성을 줄이고, 여러 노드를 하나의 프로세스 내에서 효과적으로 시작 및 관리할 수 있다. ROS2의 런치 파일은 XML이나 Python 언어로 작성되며, Python 언어가 더 자주 사용된다. Python 기반 런치 파일은 유연한 구성과 조건부 실행 등을 지원하여 대규모 시스템에서 특히 유용하다.

런치 파일의 주요 요소

  1. Node

    • Node는 런치 파일에서 가장 기본적인 구성 요소이다. 이는 실제로 실행될 ROS2 노드를 나타낸다. Node는 노드의 이름, 실행 파일 경로, 패키지, 네임스페이스, 리매핑 정보 등을 포함할 수 있다.

    ```python from launch import LaunchDescription from launch_ros.actions import Node

    def generate_launch_description(): return LaunchDescription([ Node( package='my_package', executable='my_node', name='my_node_name', namespace='my_namespace', output='screen', remappings=[('/old_topic', '/new_topic')] ) ]) ```

  2. Parameter

    • 런치 파일 내에서 노드의 파라미터를 정의할 수 있다. 파라미터는 노드 실행 시 동적으로 전달할 수 있으며, 다양한 값을 노드에 적용할 수 있다. 파라미터는 .yaml 파일로 불러오거나, 런치 파일 내에서 직접 설정할 수 있다.

    python Node( package='my_package', executable='my_node', name='my_node_name', parameters=[ {'param1': 'value1'}, {'param2': 'value2'} ] )

  3. Remap

    • 런치 파일에서는 토픽이나 서비스의 이름을 리매핑(remap)할 수 있다. 리매핑을 통해 특정 노드가 퍼블리싱하거나 구독하는 토픽의 이름을 런치 파일을 통해 변경할 수 있다.

    python Node( package='my_package', executable='my_node', remappings=[('/old_topic', '/new_topic')] )

  4. GroupAction

    • 여러 노드를 그룹으로 묶어 특정 네임스페이스에서 실행하거나, 공통 파라미터를 설정하는 데 사용할 수 있다. 이는 복잡한 시스템에서 특히 유용하다.

    ```python from launch_ros.actions import Node from launch.actions import GroupAction

    GroupAction( actions=[ Node( package='pkg1', executable='node1', name='node1', namespace='group_ns' ), Node( package='pkg2', executable='node2', name='node2', namespace='group_ns' ) ] ) ```

런치 파일 구조 및 동작

런치 파일은 노드들의 실행 정보를 담고 있는 구조이다. 런치 파일은 다음과 같은 방식으로 실행된다:

  1. launch_description() 함수:

    • 이 함수는 런치 파일이 실행될 때 반환하는 객체로, 실제 노드와 실행 명령어들을 포함하는 리스트를 반환한다.
  2. Node 설정:

    • 노드를 설정할 때 패키지 이름과 실행 파일을 명시한다. 그리고 노드의 네임스페이스, 이름, 출력 형식, 파라미터 등을 추가로 설정할 수 있다.

    python return LaunchDescription([ Node( package='my_robot', executable='robot_controller', output='screen', name='controller_node' ) ])

  3. 실행 명령어:

    • 런치 파일을 실행하기 위해서는 ros2 launch 명령어를 사용한다. 해당 명령어는 런치 파일을 불러와 ROS2 노드를 동시에 실행하는 역할을 한다.

    bash ros2 launch my_package my_launch_file.py

런치 파일에서 조건부 실행

런치 파일은 다양한 조건부 실행을 지원한다. 조건부 실행은 노드나 그룹이 특정 조건을 만족할 때만 실행되도록 설정할 수 있다. 주로 환경 변수나 파라미터의 값에 따라 달라질 수 있다.

from launch.conditions import IfCondition, UnlessCondition

Node(
    package='my_package',
    executable='my_node',
    condition=IfCondition('launch_param == true')
)

런치 파일 내의 조건부 실행을 통해 다양한 시나리오에서 유연하게 시스템을 구성할 수 있다. 조건에 따라 노드 실행을 조절하는 것은 복잡한 시스템에서 매우 유용하다.

런치 파일에서의 네임스페이스 적용

런치 파일에서 노드를 실행할 때 네임스페이스를 지정하면, 해당 노드와 관련된 모든 토픽 및 서비스가 그 네임스페이스에 포함된다. 네임스페이스를 사용하는 이유는 주로 대규모 시스템에서 같은 이름을 가진 여러 노드를 관리하거나, 로봇 그룹을 분리하여 관리할 때이다.

Node(
    package='my_robot',
    executable='robot_controller',
    namespace='robot1',
    name='controller_node'
)

위 예시에서 robot_controller 노드는 robot1이라는 네임스페이스 내에서 실행된다. 따라서, 이 노드가 퍼블리싱하는 모든 토픽 및 서비스는 /robot1/이라는 경로로 제공된다. 네임스페이스는 복잡한 멀티로봇 시스템에서 특히 유용하며, 시스템을 구분하는 데 중요한 역할을 한다.

런치 파일에서의 파라미터 전달

런치 파일을 통해 노드에 파라미터를 전달하는 것은 매우 중요한 기능이다. 파라미터를 통해 노드가 작동하는 방식을 동적으로 변경할 수 있기 때문에, 복잡한 시스템에서 여러 노드의 동작을 조절하는 데 필수적인 역할을 한다.

YAML 파일을 이용한 파라미터 설정

YAML 파일은 여러 파라미터를 한 번에 전달할 수 있는 편리한 방법이다. 런치 파일에서 YAML 파일을 불러와 파라미터로 사용할 수 있다.

Node(
    package='my_package',
    executable='my_node',
    parameters=['/path/to/params.yaml']
)

YAML 파일의 예시는 다음과 같다:

my_node:
  param1: value1
  param2: value2

런치 파일 내에서 직접 파라미터 설정

런치 파일 내에서 파라미터를 직접 설정할 수도 있다. 이 방법은 특정 파라미터를 동적으로 설정하거나 런치 파일 내에서만 사용할 때 유용하다.

Node(
    package='my_package',
    executable='my_node',
    parameters=[
        {'param1': 'value1'},
        {'param2': 'value2'}
    ]
)

리매핑 (Remapping)

리매핑은 런치 파일에서 중요하게 다루는 기능 중 하나이다. 이는 특정 토픽이나 서비스의 이름을 런치 파일을 통해 변경하는 것을 의미한다. 노드가 퍼블리싱하는 토픽이나 구독하는 토픽의 이름을 런치 파일을 통해 유연하게 조정할 수 있다.

리매핑 예시

다음 예시는 my_topicnew_topic으로 리매핑하는 방법을 보여준다:

Node(
    package='my_package',
    executable='my_node',
    remappings=[('/my_topic', '/new_topic')]
)

이렇게 리매핑을 적용하면, my_node는 원래 /my_topic이라는 토픽에 퍼블리싱할 것이지만 런치 파일을 통해 /new_topic으로 변경되어 퍼블리싱한다. 이 기능은 대규모 네트워크나 복잡한 시스템에서 토픽 경로를 변경하는 데 매우 유용하다.

그룹 내 리매핑

리매핑은 개별 노드뿐만 아니라, 그룹 내에서 여러 노드에 동시에 적용할 수도 있다. 그룹 내에서 모든 노드에 동일한 리매핑을 적용하여 코드의 가독성과 유지보수성을 높일 수 있다.

GroupAction(
    actions=[
        Node(
            package='pkg1',
            executable='node1',
            remappings=[('/old_topic', '/new_topic')]
        ),
        Node(
            package='pkg2',
            executable='node2',
            remappings=[('/old_topic', '/new_topic')]
        )
    ]
)

이렇게 하면 node1node2 모두 /old_topic/new_topic으로 리매핑하여 사용할 수 있다.

런치 파일에서의 환경 변수 설정

런치 파일을 통해 환경 변수를 설정하여 노드 실행 시 특정 설정값을 동적으로 적용할 수 있다. 환경 변수는 주로 시스템 설정을 변경하거나, 다양한 실행 환경에 맞춰 동작을 조정할 때 사용된다.

환경 변수 설정 예시

환경 변수를 런치 파일 내에서 설정하려면 SetEnvironmentVariable 명령을 사용한다. 이 명령은 특정 변수에 값을 할당하고, 노드 실행 시 이를 참조하도록 한다.

from launch.actions import SetEnvironmentVariable

def generate_launch_description():
    return LaunchDescription([
        SetEnvironmentVariable('MY_ENV_VAR', 'some_value'),
        Node(
            package='my_package',
            executable='my_node',
            name='my_node_name'
        )
    ])

위 예시에서는 MY_ENV_VAR 환경 변수를 some_value로 설정하고, 이를 참조하는 노드를 실행할 수 있다. 특정 환경 변수는 노드의 동작을 유연하게 설정할 수 있는 중요한 도구이다.

런치 파일에서 조건부 실행 및 제어

ROS2 런치 파일에서 중요한 또 다른 기능은 조건부 실행이다. 조건부 실행을 통해 노드가 특정 조건을 만족할 때만 실행되도록 설정할 수 있다. 이 기능은 복잡한 시스템에서 다양한 실행 시나리오에 따라 노드 실행을 조절하는 데 유용하다.

조건부 실행 예시

IfConditionUnlessCondition은 조건부 실행을 설정할 때 주로 사용하는 클래스이다. 예를 들어, 환경 변수가 특정 값일 때만 노드를 실행하거나, 특정 파라미터 값에 따라 노드를 실행할 수 있다.

from launch.conditions import IfCondition, UnlessCondition

Node(
    package='my_package',
    executable='my_node',
    condition=IfCondition('launch_param == true')
)

위 예시에서 launch_param 값이 true일 때만 my_node가 실행된다. 조건부 실행을 활용하면 상황에 따라 노드 실행을 제어할 수 있어 시스템의 유연성을 높일 수 있다.

런치 파일에서 멀티 노드 실행

ROS2 런치 파일의 중요한 특징 중 하나는 다수의 노드를 동시에 실행할 수 있다는 점이다. 이를 통해 하나의 런치 파일에서 여러 노드를 관리하고, 시스템의 시작 및 구성을 단순화할 수 있다.

다중 노드 실행 예시

다음은 런치 파일에서 여러 노드를 동시에 실행하는 예시이다:

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='my_package',
            executable='node1',
            name='node1_name'
        ),
        Node(
            package='my_package',
            executable='node2',
            name='node2_name'
        )
    ])

위 예시는 node1node2를 동시에 실행하는 런치 파일이다. 이와 같은 방식으로 여러 노드를 한 번에 실행하여 시스템의 초기화를 손쉽게 할 수 있다.

런치 파일에서의 타이머 사용

런치 파일에서 타이머를 설정하여 특정 시간 후에 노드를 실행할 수 있다. 이는 시스템 부팅 순서를 조절하거나, 특정 노드를 지연 실행하는 데 유용하다.

타이머 설정 예시

타이머를 사용하여 일정 시간 후에 노드를 실행하려면 TimerAction을 사용할 수 있다.

from launch.actions import TimerAction
from launch_ros.actions import Node

TimerAction(
    period=5.0,  # 5초 후 실행
    actions=[
        Node(
            package='my_package',
            executable='my_node',
            name='my_node_name'
        )
    ]
)

위 예시에서는 런치 파일이 실행된 후 5초가 지나면 my_node가 실행되도록 설정하였다. 이 기능은 노드 간의 실행 순서를 조절할 때 유용하게 사용된다.

런치 파일에서 매개변수화된 실행

ROS2 런치 파일은 동적 매개변수를 통해 노드의 실행을 매개변수화할 수 있다. 이 기능을 활용하면 런치 파일 실행 시 값을 지정하여 노드의 동작을 제어할 수 있다. 이를 통해 다양한 실행 환경과 요구 사항에 유연하게 대응할 수 있다.

LaunchArgument를 통한 매개변수 설정

런치 파일에서 매개변수를 설정하려면 LaunchArgument를 사용한다. 이는 런치 파일 실행 시 사용자로부터 값을 입력받아 해당 값에 따라 노드의 설정을 변경할 수 있도록 한다.

from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        DeclareLaunchArgument(
            'robot_name',
            default_value='robot1',
            description='Name of the robot'
        ),
        Node(
            package='my_robot',
            executable='robot_controller',
            name=[LaunchConfiguration('robot_name')]
        )
    ])

위 예시에서는 robot_name이라는 런치 매개변수를 정의하고, 런치 파일 실행 시 해당 매개변수를 사용하여 노드의 이름을 동적으로 지정할 수 있다. 매개변수를 런치 파일 실행 시 다음과 같이 전달할 수 있다:

ros2 launch my_package my_launch_file.py robot_name:=my_robot

LaunchConfiguration으로 매개변수 참조

런치 파일 내에서 매개변수를 참조하려면 LaunchConfiguration을 사용한다. LaunchConfiguration은 선언된 런치 매개변수의 값을 불러와 해당 값을 노드나 다른 런치 구성 요소에 전달한다.

from launch.substitutions import LaunchConfiguration

Node(
    package='my_robot',
    executable='robot_controller',
    name=LaunchConfiguration('robot_name')
)

이와 같이 매개변수화된 실행을 통해 다양한 조건에 맞춘 노드 실행이 가능한다.

런치 파일에서 그룹 실행 및 노드 그룹화

런치 파일에서는 여러 노드를 그룹으로 묶어 관리할 수 있다. 노드 그룹화를 통해 공통된 네임스페이스, 파라미터, 리매핑 설정 등을 일괄 적용할 수 있으며, 이를 통해 코드의 가독성과 유지보수성을 향상시킬 수 있다.

그룹 실행 예시

다음은 GroupAction을 사용하여 여러 노드를 그룹으로 묶고, 그룹 내의 모든 노드에 동일한 네임스페이스를 적용하는 예시이다:

from launch_ros.actions import Node
from launch.actions import GroupAction

def generate_launch_description():
    return LaunchDescription([
        GroupAction(
            actions=[
                Node(
                    package='pkg1',
                    executable='node1',
                    name='node1',
                    namespace='robot_ns'
                ),
                Node(
                    package='pkg2',
                    executable='node2',
                    name='node2',
                    namespace='robot_ns'
                )
            ]
        )
    ])

위 예시에서는 node1node2가 모두 robot_ns라는 네임스페이스 하에 실행된다. 이와 같은 방식으로 다수의 노드를 그룹으로 묶어 관리하는 것이 가능한다.

런치 파일에서 노드 실행 순서 제어

복잡한 시스템에서는 노드 간의 실행 순서를 제어하는 것이 중요할 때가 있다. ROS2 런치 파일은 노드 실행 순서를 제어하기 위한 다양한 방법을 제공한다. 가장 일반적으로 사용하는 방법은 타이머와 함께 노드를 실행하거나, EventHandler를 사용하여 특정 이벤트 발생 시 노드를 실행하는 것이다.

타이머를 이용한 순서 제어

이전 예시에서 설명한 타이머를 이용해 특정 노드를 지연 실행함으로써 노드 실행 순서를 제어할 수 있다. 다음은 두 개의 노드를 순차적으로 실행하는 예시이다:

from launch.actions import TimerAction
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='my_package',
            executable='node1',
            name='node1'
        ),
        TimerAction(
            period=5.0,
            actions=[
                Node(
                    package='my_package',
                    executable='node2',
                    name='node2'
                )
            ]
        )
    ])

위 예시에서는 node1이 즉시 실행되고, 5초 후에 node2가 실행된다.

이벤트 핸들러를 통한 순서 제어

또한, EventHandler를 사용하여 특정 이벤트가 발생했을 때 노드를 실행할 수도 있다. 예를 들어, 특정 노드가 종료된 후에 다른 노드를 실행할 수 있다.

from launch.actions import RegisterEventHandler, LogInfo
from launch.event_handlers import OnProcessExit
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='my_package',
            executable='node1',
            name='node1'
        ),
        RegisterEventHandler(
            event_handler=OnProcessExit(
                target_action=Node(
                    package='my_package',
                    executable='node1'
                ),
                on_exit=[
                    LogInfo(msg="node1 has exited. Starting node2..."),
                    Node(
                        package='my_package',
                        executable='node2',
                        name='node2'
                    )
                ]
            )
        )
    ])

위 예시에서는 node1이 종료된 후에 node2가 실행되도록 설정되어 있다. 이를 통해 이벤트 기반으로 노드 실행 순서를 제어할 수 있다.

런치 파일에서 조건부 실행 제어

런치 파일에서는 특정 조건을 만족하는 경우에만 노드를 실행하도록 제어할 수 있다. 조건부 실행은 환경 변수나 런치 매개변수에 따라 유연하게 설정할 수 있으며, 이를 통해 상황에 맞는 런치 파일 구성을 할 수 있다.

IfCondition과 UnlessCondition

IfConditionUnlessCondition은 조건부 실행을 설정할 때 가장 많이 사용하는 기능이다. IfCondition은 조건이 참일 때 실행되며, UnlessCondition은 조건이 거짓일 때 실행된다. 이를 통해 특정 환경 변수나 매개변수 값에 따라 노드 실행을 조절할 수 있다.

from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        DeclareLaunchArgument(
            'use_sim_time',
            default_value='false',
            description='Use simulation (Gazebo) clock if true'
        ),
        Node(
            package='my_package',
            executable='my_node',
            name='my_node',
            parameters=[{'use_sim_time': LaunchConfiguration('use_sim_time')}],
            condition=IfCondition(LaunchConfiguration('use_sim_time'))
        )
    ])

위 예시는 use_sim_time이라는 런치 매개변수의 값이 true일 때만 my_node가 실행된다. 이를 통해 시뮬레이션 환경에서만 특정 노드를 실행하거나, 물리 환경에서 실행되는 노드를 제어할 수 있다.

조건부 실행과 타이머의 결합

타이머와 조건부 실행을 결합하여 보다 복잡한 실행 로직을 만들 수 있다. 예를 들어, 특정 조건이 만족되면 일정 시간 후에 노드를 실행할 수 있다.

from launch.actions import TimerAction
from launch.conditions import IfCondition
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='my_package',
            executable='node1',
            name='node1',
            condition=IfCondition('launch_param == true')
        ),
        TimerAction(
            period=10.0,
            actions=[
                Node(
                    package='my_package',
                    executable='node2',
                    name='node2'
                )
            ],
            condition=IfCondition('launch_param == true')
        )
    ])

위 예시는 launch_paramtrue일 때만 node1이 실행되고, 10초 후에 node2가 실행된다. 이와 같이 다양한 조건과 타이머를 결합하여 복잡한 실행 흐름을 설정할 수 있다.

런치 파일에서 로깅 및 출력 관리

런치 파일을 실행할 때, 각 노드의 실행 로그나 출력을 관리하는 것이 중요하다. ROS2에서는 노드 실행 시 출력되는 로그를 화면에 출력하거나, 파일로 저장할 수 있는 다양한 옵션을 제공한다.

출력 옵션

노드 실행 시 출력을 관리하는 옵션으로 output을 사용할 수 있다. 이 옵션은 출력 형태를 설정하며, 주로 두 가지 선택이 있다:

  1. screen: 노드의 출력이 터미널 화면에 출력된다.
  2. log: 노드의 출력이 로그 파일로 저장된다.
Node(
    package='my_package',
    executable='my_node',
    name='my_node_name',
    output='screen'
)

위 예시에서는 my_node의 출력이 터미널에 바로 출력된다. 만약 출력이 로그 파일로 저장되길 원한다면 output='log'로 설정하면 된다.

로깅 레벨 설정

ROS2에서는 노드의 로깅 레벨을 설정하여 출력되는 로그의 상세 정도를 제어할 수 있다. 주요 로깅 레벨은 DEBUG, INFO, WARN, ERROR, FATAL이다. 런치 파일 내에서 로깅 레벨을 설정할 수 있으며, log_level 옵션을 사용하여 이를 제어한다.

Node(
    package='my_package',
    executable='my_node',
    name='my_node_name',
    output='screen',
    parameters=[{'log_level': 'INFO'}]
)

위 예시에서는 my_node의 로깅 레벨을 INFO로 설정하여 필요한 정보만 출력되도록 제어한다. 이를 통해 시스템의 디버깅과 모니터링에 필요한 로그 정보를 효과적으로 관리할 수 있다.

런치 파일에서의 실행 모니터링

ROS2 런치 파일은 노드 실행 상태를 모니터링하고, 실행 중에 발생하는 문제를 해결하는 데 도움을 준다. ros2 명령어를 사용하여 노드 실행 상태를 실시간으로 확인할 수 있으며, 이를 통해 노드의 동작을 관리할 수 있다.

ros2 topic과 ros2 service 명령어

ROS2의 ros2 topicros2 service 명령어를 사용하여 노드 간의 통신 상태를 실시간으로 모니터링할 수 있다. ros2 topic 명령어는 현재 노드에서 퍼블리싱 및 구독하는 토픽을 확인하고, 해당 토픽의 메시지를 실시간으로 출력할 수 있다.

ros2 topic list
ros2 topic echo /my_topic

ros2 service 명령어는 현재 노드에서 제공하는 서비스와 클라이언트를 확인하고, 서비스 요청 및 응답 상태를 모니터링할 수 있다.

ros2 service list
ros2 service call /my_service my_package/srv/MyService "{param1: value1}"

이 명령어들을 사용하여 런치 파일 실행 중 발생하는 문제를 빠르게 파악하고 해결할 수 있다.