えいあーるれいの技術日記

ROS2やM5 Stack、Ubuntuについて書いています

launchファイルでlaunchを呼び出す(ROS2)

darknet_rosに対するコードレビューがあり、「launchファイル多すぎ、もっとパラメータ付けて簡潔にしなさい」と言われてしまったので、ROS2のlaunchファイルをROS1に似た形式で書き換えることにしました。

github.com

しかし、コピペできそうなサンプルプログラムもリファレンスもなく結構困ることに…

今回はlaunchファイルをもう一つのlaunchファイルから呼び出してパラメータをより簡単に記載する方法をメモとして書こうと思います。

launch.pyファイルはPythonファイルですが、ここでは「launchファイル」と表記します。また、実行可能プログラムのことを「ノード」と読んでいます。

対象プログラム(param.cpp)

gist.github.com

launchなしで実行してみましょう。$ ros2 run launch_launch paramで実行します。

f:id:Ray_ar:20210815203040p:plain

declare_paramで設定したとおりに全て-1が返ってきました。特に特別なことはありませんね。

呼び出されるほうのlaunch.py

次に、呼び出される方のlaunchを書いていきます。

最初に呼び出されないことを前提にしたlaunchファイルを示します。

import launch
import launch_ros.actions

def generate_launch_description():
    param_node = launch_ros.actions.Node(
        package="launch_launch", executable="param", output="screen",
        parameters=[{
            "param0": 1,
            "param1": 2,
            "param2": 3,
            "param3": 4,
        }]
    )

    #列挙したアクションを実行
    return launch.LaunchDescription([
        param_node,
    ])

f:id:Ray_ar:20210815203052p:plain

次に呼び出される場合のlaunchファイルを記述していきます。呼び出されるlaunchは base.launch.py です。(呼び出す方は read_launch.launch.py です。)

gist.github.com

ここで重要なメソッドにlaunch.substitutions.LaunchConfigurationlaunch.actions.DeclareLaunchArgumentがあります。それぞれ説明します。

launch.substitutions.LaunchConfiguration

launch.substitutions.LaunchConfigurationはLaunchファイル内でパラメータや引数を変数として扱い、ノードやLaunchファイルに引数として渡すことができます。

このlaunchファイルではparam_nodeparametersへの変数にしていますが、これによって"param0"を他のアクションやlaunchファイルから扱うことができます。

launch.substitutions.LaunchConfigurationがparam.cpp固有のパラメータ"param0"外部から扱えるようにパイプを接続しているように振る舞っているといえます。

launch.actions.DeclareLaunchArgument

launch.actions.DeclareLaunchArgumentは外部からlaunchファイルを扱うときのパラメータを定義しています。

このときに、"param0"を外部から変更したい場合はlaunch.actions.DeclareLaunchArgumentの引数に"param0"を入れる必要があります。

これをlaunch.LaunchDescriptionに渡してgenerate_launch_descriptionの返り値に含めることでノードやLaunchファイルへの引数にすることができます。

ただし、このメソッド自体は宣言時点で引数宣言の役割は果たしているため、return launch.LaunchDescriptionに入れる必要はありません。入れなかった場合は、呼び出されたときのみ適用されます。(default_valueが適用されない)


実行結果を示します

f:id:Ray_ar:20210815203104p:plain

"argment0""argment1"を実際に実行しているため、"param0""param1"が1, 2になって、残りが0になっています。

そして、呼び出す方のlaunchを書いていきます。呼び出しは read_launch.launch.py で行います。

launchファイルのロードは、get_package_share_directoryを活用してインストール先のlaunchファイルを探し、PythonLaunchDescriptionSourceでロードできます。

launch.actions.IncludeLaunchDescriptionは、launchファイルをノードとほとんど同じように扱うことができます。ただし、パラメータを引数として与えることはできないため、全てlaunch_argumentsとして渡しましょう。

実行結果です。

f:id:Ray_ar:20210815203119p:plain

ちゃんと上書きができています。

まとめ

darknet_rosのlaunchファイルはyamlファイルをロードしますが、ここでは気軽に試せるように直接値を渡す例で解説しました。

ROS2のlaunchファイルの書き方はサンプルが多くなく、正しいと思ってもエラーになる場合が多いので結構つまづきポイントになるので、使えるlaunchファイルの書き方があればどんどん書いていこうと思います。

ROS2でもROS1と同様にxml形式で書くことができるそうですが、せっかくPythonで書けるのだからPythonの豊富なライブラリを活用してlaunchファイルを設計しましょう❗

以前のlaunch(Python)の設計↓

ar-ray.hatenablog.com