본문으로 바로가기

ROS2 launch 작성

category 강좌/ROS2 2026. 5. 10. 23:48

1. roslaunch 기본 개념

 

ROS 2에서 여러 노드를 실행할 때 터미널을 여러 개 열고 하나씩 실행하면 불편합니다.

 

예를 들어 다음과 같은 명령을 각각 실행해야 한다고 가정해 보겠습니다.

 
ros2 run turtlesim turtlesim_node
ros2 run my_first_package my_publisher
 

 

이런 경우 launch 파일을 만들면 한 번에 실행할 수 있습니다.

 
ros2 launch my_first_package turtlesim_and_teleop.launch.py
 

 

ROS 2의 launch 파일은 Python으로 작성하는 방식이 일반적입니다.

 

기본 구조는 다음과 같습니다.

 

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            namespace='turtlesim',
            package='turtlesim',
            executable='turtlesim_node',
            output='screen'
        ),
        Node(
            namespace='pub_cmd_vel',
            package='my_first_package',
            executable='my_publisher',
            output='screen'
        )
    ])

 

 

이 파일은 두 개의 노드를 동시에 실행합니다.

1. turtlesim 패키지의 turtlesim_node
2. my_first_package 패키지의 my_publisher

 

 

from launch import LaunchDescription
from launch_ros.actions import Node
 

 

LaunchDescription은 launch 파일에서 실행할 작업 목록을 담는 객체입니다.
즉, “어떤 노드들을 실행할 것인가?”를 정의하는 컨테이너 역할을 합니다.

 

Node는 ROS 2 노드를 launch 파일 안에서 실행하기 위한 액션입니다.
터미널에서 직접 실행하는 아래 명령과 비슷한 역할을 합니다.

 
 
def generate_launch_description():
 

 

ROS 2 launch 파일에서 반드시 사용되는 함수입니다.

ROS 2는 launch 파일을 실행할 때 이 함수를 찾아서 호출합니다.
그리고 이 함수가 반환하는 LaunchDescription 안의 내용을 기준으로 노드들을 실행합니다.

즉, 이 함수는 launch 파일의 시작점이라고 보면 됩니다.

 

return LaunchDescription([
 

LaunchDescription 객체를 반환합니다.

대괄호 [] 안에는 실행할 노드나 액션들이 들어갑니다.
현재 코드에서는 두 개의 Node가 등록되어 있습니다.

 

 

 

 

1) 첫 번째 Node 설명

 
Node(
    namespace='turtlesim',
    package='turtlesim',
    executable='turtlesim_node',
    output='screen'
),
 

 

이 부분은 turtlesim 패키지의 turtlesim_node를 실행합니다.

 

터미널 명령으로 표현하면 대략 아래와 같습니다.

 
ros2 run turtlesim turtlesim_node
 

 

하지만 여기서는 namespace='turtlesim'이 추가되어 있기 때문에 실제 노드와 토픽 이름 앞에 /turtlesim 네임스페이스가 붙습니다.

 

예를 들어 일반적으로 turtlesim 노드를 실행하면 토픽 이름이 다음처럼 나옵니다.

 
/turtle1/cmd_vel
/turtle1/pose
 

 

하지만 이 launch 파일에서는 네임스페이스가 적용되어 다음처럼 됩니다.

 
/turtlesim/turtle1/cmd_vel
/turtlesim/turtle1/pose
 

 

즉, namespace='turtlesim'은 이 노드가 사용하는 이름 공간을 /turtlesim 아래로 묶어주는 역할을 합니다.

 

 

 

2) 두 번째 Node 설명

 
Node(
    namespace='pub_cmd_vel',
    package='my_first_package',
    executable='my_publisher',
    output='screen'
)
 

 

이 부분은 사용자가 만든 패키지인 my_first_package 안의 my_publisher 실행 파일을 실행합니다.

 

터미널 명령으로 표현하면 대략 아래와 같습니다.

 
ros2 run my_first_package my_publisher
 

 

여기에도 네임스페이스가 지정되어 있습니다.

 
namespace='pub_cmd_vel'
 
 

따라서 이 노드는 /pub_cmd_vel 네임스페이스 안에서 실행됩니다.

 

예를 들어 my_publisher 노드가 cmd_vel이라는 토픽을 발행한다면, 실제 토픽 이름은 다음처럼 될 수 있습니다.

 
/pub_cmd_vel/cmd_vel
 

 

단, 이것은 my_publisher 코드 안에서 토픽 이름을 어떻게 작성했는지에 따라 달라집니다.

 

예를 들어 코드 안에서 상대 토픽 이름을 사용했다면:

 
self.create_publisher(Twist, 'cmd_vel', 10)
 

 

launch 파일의 네임스페이스가 적용되어 실제 토픽은 다음처럼 됩니다.

 
/pub_cmd_vel/cmd_vel
 

 

반대로 절대 토픽 이름을 사용했다면:

 
self.create_publisher(Twist, '/turtle1/cmd_vel', 10)
 

 

이 경우에는 네임스페이스의 영향을 받지 않고 그대로 /turtle1/cmd_vel이 됩니다.

 

 

 

 

3) package의 의미

 
package='turtlesim'
 

 

또는

 
package='my_first_package'
 

 

package는 실행할 노드가 들어 있는 ROS 2 패키지 이름입니다.

 

예를 들어:

 
package='turtlesim'
 

 

은 turtlesim 패키지 안에서 실행 파일을 찾겠다는 뜻입니다.

 
package='my_first_package'
 

 

은 사용자가 만든 my_first_package 패키지 안에서 실행 파일을 찾겠다는 뜻입니다.

 

 

 

4) executable의 의미

 
executable='turtlesim_node'
 

 

또는

 
executable='my_publisher'
 

 

executable은 실제 실행할 프로그램(노드) 이름입니다.

 

즉, 아래 명령에서 마지막 부분에 해당합니다.

 
ros2 run turtlesim turtlesim_node
 

 

여기서:

 
turtlesim
 

 

은 패키지 이름이고,

 
turtlesim_node
 

 

는 실행 파일 이름입니다.

 

 

 

5) namespace의 의미

 
namespace='turtlesim'
 
 
namespace='pub_cmd_vel'
 

 

namespace는 노드 이름과 토픽 이름 앞에 붙는 이름 공간입니다.

 

네임스페이스를 사용하는 이유는 여러 노드나 여러 로봇을 동시에 실행할 때 이름 충돌을 막기 위해서입니다.

 

예를 들어 로봇 두 대를 실행한다고 하면:

 
/robot1/cmd_vel
/robot2/cmd_vel
 

처럼 분리할 수 있습니다.

 

이 코드에서는 turtlesim 노드는 /turtlesim 아래에, publisher 노드는 /pub_cmd_vel 아래에 들어갑니다.

 

만약 namespace를 사용하지 않는다면 namespace=''로 정의가 가능한데 namespace를 생략하는 것이 정석입니다.

 

 

 

 

6) output='screen'의 의미

 
output='screen'
 

 

노드에서 출력하는 로그를 터미널 화면에 보여주겠다는 뜻입니다.

 

예를 들어 노드 코드 안에 다음과 같은 로그가 있다면:

 
self.get_logger().info('Publishing cmd_vel')
 

 

launch 실행 터미널에 출력됩니다.

 

만약 output='screen'이 없다면 로그가 화면에 바로 보이지 않거나 launch 시스템 내부 로그로만 저장될 수 있습니다.

 

개발 중에는 보통 output='screen'을 넣는 것이 좋습니다.


문제 찾기가 훨씬 쉽습니다.

 

 

 

 

2. launch 파일 폴더 만들기

 

패키지 안에 launch 파일을 넣기 위해 다음 구조를 사용합니다.

my_first_package/
├── launch/
│   └── turtlesim_and_teleop.launch.py
├── my_first_package/
│   ├── my_publisher.py
│   └── ...
├── package.xml
└── setup.py
 

 

launch 폴더를 만든 뒤 그 안에 .launch.py 파일을 작성합니다.

 

터미널을 실행하여 아래을 명령을 실행합니다.

 

cd ~/ros2_study/src/my_first_package/

mkdir launch

touch launch/turtlesim_and_teleop.launch.py

 

 

 

파일명 예시는 다음과 같습니다.

turtlesim_and_teleop.launch.py
dist_turtle_action.launch.py

 

 

code를 실행하고 turtlesim_and_teleop.launch.py 파일을 작성합니다.

 

 

 

3. setup.py에 launch 파일 등록하기

 

Python 기반 ROS 2 패키지에서는 launch 파일을 설치 대상에 포함해야 합니다.

 

setup.py에 다음 구문이 필요합니다.

 

import os
import glob
from setuptools import setup

package_name = 'my_first_package'

setup(
    name=package_name,
    version='0.0.0',
    packages=[package_name],
    data_files=[
        (
            'share/ament_index/resource_index/packages',
            ['resource/' + package_name]
        ),
        (
            'share/' + package_name,
            ['package.xml']
        ),
        (
            'share/' + package_name + '/launch',
            glob.glob(os.path.join('launch', '*.launch.py'))
        ),
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='pw',
    maintainer_email='pw@todo.todo',
    description='TODO: Package description',
    license='TODO: License declaration',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
            'my_first_node = my_first_package.my_first_node:main',
            'my_subscriber = my_first_package.my_subscriber:main',
            'my_publisher = my_first_package.my_publisher:main',
            'dist_turtle_action_server = my_first_package.dist_turtle_action_server:main',
        ],
    },
)

 

 

아래의 부분이 핵심입니다.

 

먼저 glob를 import 합니다.

 

import os
import glob

 

 

(
    'share/' + package_name + '/launch',
    glob.glob(os.path.join('launch', '*.launch.py'))
),

 

더보기

위의 코드는 ROS 2 Python 패키지의 setup.py에서 launch 파일들을 설치 경로로 복사하도록 지정하는 부분입니다.

 

현재 패키지 폴더 안의 launch 디렉토리에 있는 모든 *.launch.py 파일을 찾아서, ROS 2 설치 공간의 share/패키지이름/launch 폴더에 복사하라는 의미입니다.

 

이 코드는 패키지를 빌드할 때,

launch/*.launch.py
 

 

형태의 파일들을 찾아서 ROS 2 설치 공간 안의 다음 경로( package_name = 'mobile_robot_bringup' )로 복사합니다.

install/mobile_robot_bringup/share/mobile_robot_bringup/launch/
 

 

즉, 패키지 안에 있는 launch 파일을 ROS 2가 실행할 수 있는 위치로 설치하는 역할입니다.

 

 

os.path.join('launch', '*.launch.py')
 

 

이 부분은 파일 검색 패턴을 만듭니다.

 

결과적으로 다음과 같은 문자열이 됩니다.

launch/*.launch.py
 

 

즉, launch 폴더 안에 있는 모든 .launch.py 파일을 의미합니다.

 

예를 들어 패키지 구조가 다음과 같다면:

mobile_robot_bringup/
├── setup.py
├── package.xml
├── mobile_robot_bringup/
│   └── __init__.py
└── launch/
    ├── robot_bringup.launch.py
    ├── navigation.launch.py
    └── slam.launch.py
 

 

다음 파일들이 검색됩니다.

launch/robot_bringup.launch.py
launch/navigation.launch.py
launch/slam.launch.py
 
 

 

 
 

glob.glob()은 조건에 맞는 파일 목록을 리스트로 반환합니다.

 

예를 들어:

 
glob.glob(os.path.join('launch', '*.launch.py'))
 

의 결과는 다음처럼 됩니다.

 
[
    'launch/robot_bringup.launch.py',
    'launch/navigation.launch.py',
    'launch/slam.launch.py'
]

 

 

 

 

 

이 설정이 없으면 빌드 후 ros2 launch에서 launch 파일을 찾지 못할 수 있습니다.

 

 

 

4. 빌드 및 실행

 

파일을 수정한 뒤에는 반드시 다시 빌드합니다.

 

cd ~/ros2_study
colcon build --packages-select my_first_package

 

 

 

만약에 ~/ros2_study/install/my_first_package/share/my_first_package/launch 위치에 turtlesim_and_teleop.launch.py 파일이 존재하지 않을 경우, 아래의 명령을 실행하여 다시 빌드합니다.

 

cd ~/ros2_study
colcon build --packages-select my_first_package --symlink-install

 

 

환경을 다시 적용합니다.

 

source install/setup.bash

 

 

새로운 터미널을 실행하여 launch 파일을 실행합니다.

 

ros2 launch my_first_package turtlesim_and_teleop.launch.py

 

정상적으로 실행되면 하나의 터미널에서 여러 노드의 로그가 함께 출력됩니다.

 

 

 

 

 

5. launch 파일에서 파라미터 지정하기

 

launch 파일에서는 노드 실행뿐 아니라 파라미터도 지정할 수 있습니다.

예를 들어 turtlesim 배경색을 바꾸고 싶다면 다음처럼 작성합니다.

 

turtlesim_node = Node(
    package='turtlesim',
    executable='turtlesim_node',
    output='screen',
    parameters=[
        {'background_r': 255},
        {'background_g': 192},
        {'background_b': 203},
    ]
)

 

 

이 설정은 turtlesim 배경색을 RGB 값으로 지정하는 예시입니다.

background_r = 255
background_g = 192
background_b = 203
 

 

즉, launch 파일에서 노드를 실행하면서 동시에 초기 설정값까지 넣을 수 있습니다.

 

 

 

6. action Server까지 함께 실행하는 launch 파일

 

turtlesim_node와 사용자 정의 액션 서버를 함께 실행하고 싶다면 다음처럼 구성할 수 있습니다.

 

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    turtlesim_node = Node(
        package='turtlesim',
        executable='turtlesim_node',
        output='screen',
        parameters=[
            {'background_r': 255},
            {'background_g': 192},
            {'background_b': 203},
        ]
    )

    dist_turtle_action_node = Node(
        package='my_first_package',
        executable='dist_turtle_action_server',
        output='screen'
    )

    return LaunchDescription([
        turtlesim_node,
        dist_turtle_action_node
    ])

 

 

launch 파일을 만들었던 폴더로 이동하여 dist_turtle_action.launch.py 파일을 생성합니다.

 

cd ~/ros2_study/src/my_first_package/launch/

touch dist_turtle_action.launch.py

 

 

dist_turtle_action.launch.py 팡리을 열고 위의 소스 코드를 입력하고 저장합니다.

 

 

my_first_packge를 다시 빌드합니다.

 

cd ~/ros2_study
colcon build --packages-select my_first_package --symlink-install

 

 

환경을 다시 적용합니다.

 

source install/setup.bash

 

 

새로운 터미널을 실행하여 launch 파일을 실행합니다.

 

이렇게 하면 turtle 시뮬레이터와 액션 서버가 동시에 실행됩니다.

ros2 launch my_first_package dist_turtle_action.launch.py

 

 

 

 

/ros2_study/install/my_first_package/share/my_first_package/launch 위치에 2개의 launch 파일이 존재합니다.

 

 

 

 

7. launch가 필요한 이유

 

ROS 2 프로젝트가 커지면 노드가 하나만 있는 경우는 거의 없습니다.

 

예를 들어 이동로봇 시스템이라면 다음 노드들이 동시에 실행될 수 있습니다.

모터 제어 노드
거리 센서 입력 노드
IMU 필터 노드
경로 계획 노드
미션 제어 노드
카메라 인식 노드
그리퍼 제어 노드
상태 LED 노드
로그 기록 노드
 

 

이 노드들을 매번 터미널에서 하나씩 실행하는 것은 비효율적입니다.


launch 파일은 이런 노드 실행을 자동화하는 역할을 합니다.

 

그리고 여러 개의 launch 파일을 자동으로 실행해 주는 tmux도 유용하게 사용됩니다.

 

 

 

728x90
728x90