1. 다중 노드 실행 개요

ROS2에서 여러 노드를 동시에 실행할 때, 런치 파일을 활용하여 다중 노드를 실행할 수 있다. 런치 파일을 통해 각 노드의 실행 순서를 정의하고, 실행 환경 및 파라미터를 설정할 수 있다. 여러 노드를 동시에 실행하는 것은 분산된 로봇 시스템이나 복잡한 작업을 처리하는 데 필수적이다.

2. 런치 파일을 통한 다중 노드 실행

런치 파일에서 다중 노드를 실행하기 위해서는 각각의 노드에 대한 정보를 명시적으로 정의해야 한다. 노드를 정의할 때는 노드 이름, 실행 파일 경로, 파라미터, 네임스페이스 등을 지정할 수 있다.

다음은 간단한 예시이다:

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='package_name',
            executable='node1_executable',
            name='node1',
            output='screen'
        ),
        Node(
            package='package_name',
            executable='node2_executable',
            name='node2',
            output='screen'
        ),
    ])

이 예시에서는 package_name 패키지에 속한 node1_executablenode2_executable 두 개의 노드를 런치 파일에서 동시에 실행하고 있다. 노드의 출력은 screen으로 지정되어 터미널에 출력된다.

3. 런치 파일에서의 노드 파라미터 설정

다중 노드를 실행할 때 각 노드마다 고유의 파라미터를 설정할 수 있다. 파라미터는 런치 파일에서 정의할 수 있으며, 각 노드에 대해 별도로 지정된다.

Node(
    package='package_name',
    executable='node_executable',
    name='node_name',
    parameters=[
        {'param1': 'value1'},
        {'param2': 'value2'}
    ]
)

위 코드에서 param1param2는 해당 노드에서 사용할 파라미터로 설정되며, 실행 중에 동적으로 사용할 수 있다.

4. 그룹 실행 개요

그룹 실행은 여러 노드를 한 그룹으로 묶어 실행하는 방법이다. 이를 통해 노드 간 네임스페이스, 파라미터 공유, 실행 조건을 더욱 효율적으로 관리할 수 있다. 그룹 실행은 주로 네임스페이스나 특정 조건 하에 묶여야 하는 노드를 다룰 때 유용하다.

그룹을 정의하는 기본 구조는 다음과 같다:

from launch_ros.actions import PushRosNamespace

group = GroupAction([
    PushRosNamespace('group_namespace'),
    Node(
        package='package_name',
        executable='node1_executable',
        name='node1',
    ),
    Node(
        package='package_name',
        executable='node2_executable',
        name='node2',
    ),
])

이 예시에서는 group_namespace라는 네임스페이스 내에서 node1node2를 그룹화하여 실행하고 있다.

5. 그룹 실행에서 네임스페이스의 역할

그룹 실행에서 네임스페이스는 중요하다. 각각의 노드를 네임스페이스로 묶으면 노드 이름 충돌을 피할 수 있으며, 논리적인 구조를 제공하여 노드 간 통신을 더 체계적으로 관리할 수 있다.

노드의 네임스페이스를 설정할 때는 PushRosNamespace 클래스를 사용한다. 각 그룹 내에서 동일한 네임스페이스를 공유하는 노드들은 통신 시 네임스페이스가 자동으로 포함된다.

다음과 같은 방식으로 네임스페이스를 설정할 수 있다:

PushRosNamespace('namespace_name')

여기에서 namespace_name은 그룹 내의 모든 노드에 적용되는 네임스페이스이다.

6. 조건부 실행

다중 노드 실행이나 그룹 실행 시, 특정 조건에 따라 노드를 실행하거나 실행하지 않을 수 있다. 이를 위해 ROS2 런치 파일에서 조건문을 활용할 수 있다. 주로 IfConditionUnlessCondition을 사용하여 특정 조건에 따라 노드 실행 여부를 결정할 수 있다.

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

Node(
    package='package_name',
    executable='node_executable',
    name='node_name',
    condition=IfCondition('condition_expression')
)

위 예시에서는 condition_expression이 참일 경우에만 해당 노드를 실행한다. IfCondition 외에도 반대로 조건이 거짓일 때 실행하는 UnlessCondition도 사용할 수 있다.

7. 그룹 실행의 활용 예시

그룹 실행은 복잡한 시스템에서 자주 사용된다. 예를 들어, 다중 로봇 시스템을 구성할 때 각 로봇마다 동일한 노드를 실행해야 하지만, 로봇 간의 충돌을 피하기 위해 서로 다른 네임스페이스를 사용하는 경우가 있다. 이를 런치 파일에서 그룹을 통해 간단히 구현할 수 있다.

from launch import LaunchDescription
from launch_ros.actions import PushRosNamespace, Node

def generate_launch_description():
    return LaunchDescription([
        PushRosNamespace('robot1'),
        Node(
            package='robot_control',
            executable='control_node',
            name='controller',
        ),
        PushRosNamespace('robot2'),
        Node(
            package='robot_control',
            executable='control_node',
            name='controller',
        ),
    ])

이 예시에서는 두 개의 로봇(robot1, robot2) 각각에 동일한 control_node 노드를 실행하지만, 서로 다른 네임스페이스를 사용하여 실행된다. 이를 통해 두 로봇 간의 노드 이름 충돌을 방지할 수 있다.

8. 런치 파일에서 매개변수 전달

다중 노드를 실행할 때, 각 노드에 공통적인 파라미터를 전달하거나 그룹별로 다른 파라미터를 설정할 수 있다. 이를 통해 더욱 유연한 노드 실행 환경을 구성할 수 있다.

다음은 그룹 내에서 파라미터를 전달하는 예시이다:

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

def generate_launch_description():
    return LaunchDescription([
        GroupAction([
            PushRosNamespace('robot_group'),
            Node(
                package='robot_package',
                executable='robot_node',
                name='robot1',
                parameters=[
                    {'robot_speed': '1.0'},
                    {'robot_size': 'large'}
                ]
            ),
            Node(
                package='robot_package',
                executable='robot_node',
                name='robot2',
                parameters=[
                    {'robot_speed': '0.5'},
                    {'robot_size': 'small'}
                ]
            )
        ])
    ])

위 예시에서 두 개의 로봇 노드 robot1robot2는 각각 다른 파라미터(robot_speed, robot_size)를 전달받아 실행된다.

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

다중 노드를 실행할 때 환경 변수를 설정하여 노드의 동작을 제어할 수 있다. 환경 변수는 런치 파일에서 직접 정의할 수 있으며, 이를 통해 런치 파일이 실행되는 동안의 실행 환경을 동적으로 설정할 수 있다.

환경 변수를 설정하는 기본적인 방법은 다음과 같다:

from launch.actions import SetEnvironmentVariable
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        SetEnvironmentVariable('ROS_LOG_LEVEL', 'DEBUG'),
        Node(
            package='package_name',
            executable='node_executable',
            name='node_name'
        )
    ])

이 예시에서는 ROS_LOG_LEVEL 환경 변수를 DEBUG로 설정하여 노드 실행 중에 디버그 수준의 로그가 출력되도록 한다.

10. 런치 파일에서 조건부 그룹 실행

그룹 실행 역시 조건을 걸어 실행할 수 있다. 예를 들어, 특정 조건에 따라 그룹 전체의 실행을 제어할 수 있다. 조건부 그룹 실행은 시스템의 특정 상태에 따라 그룹 내의 노드를 선택적으로 실행할 때 유용하다.

조건부 그룹 실행은 다음과 같이 구현할 수 있다:

from launch.actions import GroupAction
from launch.conditions import IfCondition
from launch_ros.actions import PushRosNamespace, Node

def generate_launch_description():
    return LaunchDescription([
        GroupAction([
            PushRosNamespace('robot1'),
            Node(
                package='robot_control',
                executable='control_node',
                name='controller1',
            ),
            Node(
                package='robot_sensors',
                executable='sensor_node',
                name='sensor1',
            ),
        ], condition=IfCondition('condition_expression'))
    ])

이 코드에서 condition_expression이 참일 경우에만 그룹 내의 노드들이 실행된다. 이를 통해 다중 노드 실행 시 특정 조건에 따라 그룹 실행을 유연하게 제어할 수 있다.

11. 그룹 실행의 동기화

여러 노드를 그룹화하여 실행할 때, 각 노드의 실행 순서를 제어하거나 동기화할 필요가 있다. 특히 로봇 시스템에서는 센서 노드와 제어 노드가 특정 순서로 실행되어야 할 수 있다. 이를 위해 런치 파일에서 TimerAction을 사용하여 특정 시간 간격을 두고 노드를 실행할 수 있다.

다음은 동기화를 위한 예시이다:

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

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='package_name',
            executable='sensor_node',
            name='sensor_node'
        ),
        TimerAction(
            period=5.0,
            actions=[Node(
                package='package_name',
                executable='control_node',
                name='control_node'
            )]
        )
    ])

이 예시에서는 sensor_node가 먼저 실행되고, 5초 후에 control_node가 실행된다. 이를 통해 노드 간 실행 순서를 제어할 수 있다.

12. 런치 파일에서 조건부 실행을 통한 다중 노드 그룹 제어

조건부 실행과 그룹 실행을 결합하여 복잡한 시스템을 구성할 수 있다. 예를 들어, 여러 노드를 그룹으로 묶고, 특정 조건에 따라 해당 그룹을 실행할지 여부를 제어할 수 있다. 이러한 방식은 다양한 환경에서 시스템을 더 유연하게 관리할 수 있게 해준다.

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

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='package_name',
            executable='node1_executable',
            name='node1',
            condition=IfCondition('use_node1')
        ),
        Node(
            package='package_name',
            executable='node2_executable',
            name='node2',
            condition=UnlessCondition('use_node2')
        ),
    ])

위 예시에서는 use_node1 조건이 참일 경우 node1_executable이 실행되고, use_node2 조건이 거짓일 경우 node2_executable이 실행된다. 이러한 조건부 실행은 런치 파일에서 노드 실행의 유연성을 크게 향상시킨다.

13. 런치 파일에서 그룹화된 노드의 순차적 실행

런치 파일에서 그룹 내 노드들을 순차적으로 실행하는 방법도 존재한다. 주로 시간 간격이나 실행 조건에 따라 노드를 차례대로 실행할 때 TimerAction을 활용할 수 있다. 이를 통해 각 노드가 실행될 타이밍을 제어하거나, 서로 다른 노드가 의존성을 가지고 실행되어야 하는 경우에 유용하게 사용된다.

예를 들어, 첫 번째 노드가 실행된 후에 두 번째 노드를 실행할 수 있다:

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

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='sensor_package',
            executable='sensor_node',
            name='sensor_node',
        ),
        TimerAction(
            period=3.0,
            actions=[Node(
                package='control_package',
                executable='control_node',
                name='control_node',
            )]
        ),
    ])

위 예시에서 sensor_node가 먼저 실행되고, 3초 후에 control_node가 실행된다. 이를 통해 특정 작업이 먼저 완료된 후 다음 작업을 실행하도록 노드 간 순서를 제어할 수 있다.

14. 런치 파일에서 노드 간 의존성 설정

노드 간 의존성을 설정하는 것은 로봇 시스템에서 중요한 부분이다. 예를 들어, 센서 데이터를 수집하는 노드가 완전히 실행된 후에 제어 노드가 데이터를 기반으로 작업을 수행해야 할 수 있다. 이를 런치 파일에서 설정할 수 있는 방법 중 하나는 RequiredAction을 사용하는 것이다.

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

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='sensor_package',
            executable='sensor_node',
            name='sensor_node',
            output='screen',
        ),
        RequiredAction(
            condition=lambda: True,
            actions=[Node(
                package='control_package',
                executable='control_node',
                name='control_node',
                output='screen',
            )]
        )
    ])

위 코드는 sensor_node가 실행된 후에만 control_node가 실행되는 방식으로 구성된다. 노드 간 의존성이 있을 때 이러한 방법으로 순차적인 실행을 보장할 수 있다.

15. 다중 노드 그룹화의 효율적 사용

다중 노드 그룹화는 로봇 시스템에서 여러 개의 동일한 노드 그룹을 생성하고, 각 그룹이 다른 파라미터나 네임스페이스를 통해 독립적으로 작동하도록 할 때 특히 유용하다. 예를 들어, 여러 대의 로봇이 동일한 제어 노드를 실행하지만 서로 다른 환경에서 작동할 수 있다.

다음은 여러 대의 로봇을 위한 그룹화된 노드 실행 예시이다:

from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import GroupAction, PushRosNamespace

def generate_launch_description():
    return LaunchDescription([
        GroupAction([
            PushRosNamespace('robot1'),
            Node(
                package='robot_control',
                executable='controller_node',
                name='controller1',
            ),
            Node(
                package='robot_sensors',
                executable='sensor_node',
                name='sensor1',
            ),
        ]),
        GroupAction([
            PushRosNamespace('robot2'),
            Node(
                package='robot_control',
                executable='controller_node',
                name='controller2',
            ),
            Node(
                package='robot_sensors',
                executable='sensor_node',
                name='sensor2',
            ),
        ]),
    ])

이 코드에서는 robot1robot2 네임스페이스 내에서 각각의 제어 및 센서 노드가 독립적으로 실행된다. 그룹화를 통해 여러 노드 간의 충돌을 방지하면서 동일한 구조의 시스템을 반복적으로 구성할 수 있다.