launchによる複数のノードの起動

launchによる複数のノードを同時に起動する方法について学びます.

目的

ros2 runによりノードを起動できますが,幾つものノードを立ち上げる際には手間となります. このような手間を解決するものとして予め定義したノード群を起動するlaunchと呼ばれる仕組みが用意されています. 今回はlaunchの使い方について学びます.

launch

ros2 runにてノードを起動する方法を学びました. 実機を使う際には,たくさんのノードを起動しなければならず,かなり手間がかかるので非効率的です. ROS2では効率化するための方法としてlaunchが用意されています. launchを使うことで,パラメータを設定した複数のノードを一括して起動することができます. 便利なコマンドですので扱えるように学びましょう.

今回は,turtlesimパッケージに含まれるシミュレーターturtlesim_nodeを2つ,そしてキーボードで操作できるturtle_teleop_keyをlaunchにより同時に起動します.

xtermのインストール

launchファイルの実行にxtermが必須ではありませんが,今回の演習で使用しますのでインストールしましょう.

1
$ sudo apt install xterm

launchファイルの作成

既に作成済みのワークスペースpractice_wsの中にlaunch_practiceという名前のパッケージを作成します.

1
2
$ cd practice_ws/src
$ ros2 pkg create --build-type ament_python launch_practice

パッケージディレクトリの中にlaunchディレクトリを作成します.

1
2
3
$ cd launch_practice
$ mkdir launch
$ cd launch

launchディレクトリに移動したら,launchファイルを作成します. launchファイルは, 今回はturtlesim_and_teleop_launch.pyという名前のlaunchファイルを作成します. launchファイルをpython言語により作成しますが,他にもXMLやYAML等で記述することが可能です. ファイル名の最後に_launchが必要となるので注意してください.

1
$ vim turtlesim_and_teleop_launch.py

テキストエディタでturtlesim_and_teleop_launch.pyを開いたら,下記の内容を入力してください.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package = 'turtlesim',
            executable = 'turtlesim_node',
        ),
        Node(
            namespace="sim1",
            package = 'turtlesim',
            executable = 'turtlesim_node',
        ),
        Node(
            package = 'turtlesim',
            executable = 'turtle_teleop_key',
            prefix = 'xterm -e',
        ),
    ])

作成したプログラムを詳しくみていきます.

1
2
from launch import LaunchDescription
from launch_ros.actions import Node

launchファイルには,launchlaunch_rosをインポートする必要があります.

4
5
def generate_launch_description():
    return LaunchDescription([

LaunchDescriptionオブジェクトをリターンするgenerate_launch_description関数が必要です. return文の中に起動するノードについて記述します.

6
7
8
9
        Node(
            package = 'turtlesim',
            executable = 'turtlesim_node',
        ),

Node()にノードの設定を記述します. packageにはパッケージ名,executableにはノード名を記述します.

10
11
12
13
14
        Node(
            namespace="sim1",
            package = 'turtlesim',
            executable = 'turtlesim_node',
        ),

通常,同一の名前を持つノードを同時に起動すると警告が表示されます. しかし,同じロボットやセンサを2個以上使いたいケースもあります. そのような場合には,名前空間(namespace)を使用します. 上記の場合には,sim1という名前空間の中に存在するturtlesimノードという意味となります. 異なる名前空間に属する同じノードの名前であれば,別々のノードとして認識できるため,警告は表示されません.

15
16
17
18
19
        Node(
            package = 'turtlesim',
            executable = 'turtle_teleop_key',
            prefix = 'xterm -e',
        ),

turtlesimパッケージのturtle_teleop_keyを起動します. prefixとしてxterm -eを与えていますが,これはxtermという端末を起動するという意味です. 起動するノードからキーボード入力したい時に利用します.

Node()の中にpackageexecutableは記述が必須となりますが,namespaceprefixはオプションとなります. 他にもパラメータの設定やリマップ等を行うことができます. 詳細を知りたい方は公式のドキュメントを参考にしてください.

次にsetup.pyファイルを編集します.

1
2
$ cd ../
$ vim setup.py

pythonでは,setup.pyファイルに依存するパッケージやエントリーポイントを記述します. 今回はハイライトの文を追加します.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from setuptools import find_packages, setup
import os
from glob import glob

package_name = 'launch_practice'

setup(
    name=package_name,
    version='0.0.0',
    packages=find_packages(exclude=['test']),
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
        (os.path.join('share', package_name), glob('launch/*launch.[pxy][yma]*')),
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='yuu',
    maintainer_email='yuu@todo.todo',
    description='TODO: Package description',
    license='TODO: License declaration',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
        ],
    },
)

2行目はOSモジュール,3行目はパスの取得に使います. 2つとも良く利用されるモジュールです. 15行目は,launchファイルが存在するパスを追加するために記述しています.

ここまでの作業が完了したらビルドしましょう.

1
2
$ cd ../../
$ colcon build

ビルド後には,以前と同様にsetup.bashをsourceにより実行します.

1
$ source install/setup.bash

最後にlaunchファイルを実行します. まずはlaunchの使い方を学ぶためにヘルプを確認してみましょう.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
$ ros2 launch -h
usage: ros2 launch [-h] [-n] [-d] [-p | -s] [-a]
                   [--launch-prefix LAUNCH_PREFIX]
                   [--launch-prefix-filter LAUNCH_PREFIX_FILTER]
                   package_name [launch_file_name] [launch_arguments ...]

Run a launch file

positional arguments:
  package_name          Name of the ROS package which contains the launch
                        file
  launch_file_name      Name of the launch file
  launch_arguments      Arguments to the launch file; '<name>:=<value>' (for
                        duplicates, last one wins)

options:
  -h, --help            show this help message and exit
  -n, --noninteractive  Run the launch system non-interactively, with no
                        terminal associated
  -d, --debug           Put the launch system in debug mode, provides more
                        verbose output.
  -p, --print, --print-description
                        Print the launch description to the console without
                        launching it.
  -s, --show-args, --show-arguments
                        Show arguments that may be given to the launch file.
  -a, --show-all-subprocesses-output
                        Show all launched subprocesses' output by overriding
                        their output configuration using the
                        OVERRIDE_LAUNCH_PROCESS_OUTPUT envvar.
  --launch-prefix LAUNCH_PREFIX
                        Prefix command, which should go before all
                        executables. Command must be wrapped in quotes if it
                        contains spaces (e.g. --launch-prefix 'xterm -e gdb
                        -ex run --args').
  --launch-prefix-filter LAUNCH_PREFIX_FILTER
                        Regex pattern for filtering which executables the
                        --launch-prefix is applied to by matching the
                        executable name.

今回はpackage_nameにはlaunch_practicelaunch_file_nameにはturtlesim_and_teleop_launch.pyとなります. 今回は引数を必要としないためlaunch_argumentsは入力しません. それでは実行してみましょう.

1
$ ros2 launch launch_practice turtlesim_and_teleop_launch.py

実行するとロボットシミュレータturtlesimの画面が2つ,ターミナルxtermが起動します. 試しにnode listで起動しているノードを確認します.

1
2
3
4
ros2 node list 
/sim1/turtlesim
/teleop_turtle
/turtlesim

以前と同様に/turtlesim/teleop_turtleは確認できますが,新たに/sim1/turtlesimが増えました. これは名前空間を指定したturtlesimです. 名前空間(今回はsim1)の後に/ノード名で実行されます.

最後にターミナルxtermを用いてロボットを操作してみましょう. ・turtlesimしかロボットが動きません. teleop_turtleからは/turtle1/cmd_velしか送らないためです. /sim1/turtlesimを操作するには,/sim1/turtle1/cmd_velを送信する必要があります.