⚔️

ROS 2 launchをXML / YAMLで記述する

2023/08/21に公開

海洋ロボコンをやってた人です。

今回はROS 2 のローンチファイルをPythonファイルではなくXML / YAML形式で記述し、Rviz2やGazeboを起動してみたので、その備忘録を記載していきます。

なぜまとめるかは以下です。

  • ROS 1はXML形式記述なので、ROS 2でも同様の形式で記述することで可読性を上げたい
  • PythonファイルをROS 2パッケージから無くしてみたい
  • YAML形式で簡潔にlaunchファイルを記述したい


一方、公式ドキュメント:Using Python, XML, and YAML for ROS 2 Launch Filesに記載もあるように、Pythonでlaunchを記述することで柔軟なlaunchのファイルを作成できるという利点もあります。
このあたりの利点・欠点を理解した上で、各々使用するのが良いと思います。

また、ROS 1のlaunchをROS 2に移植する際は公式ドキュメント:Migrating launch files from ROS 1 to ROS 2も参照してください。

環境はUbuntu 22.04 HumbleでURDFモデルをRviz2とGazeboにスポーンするXMLを想定しています。

自作ノードをXMLで起動させる場合は、Referencesを参考に解読してください。

本記事に対するコメントも積極的に募集しますので、よろしくお願いいたします。

※ 追記 2023/8/21

https://twitter.com/porizou1/status/1693604473334300817

ということなので、

https://github.com/autowarefoundation/autoware.universe/tree/main/launch

XMLでlaunchを書きたければ、Autowareを学ぶのが良さそうです。

XML launchでRviz2を起動する

まずはROS 1でRvizを起動するXMLを記載しておきます。

dispaly.launch
<launch>
  <arg name="model" default="$(find fish_robot_description)/urdf/fish_robot.xacro"/>
  <arg name="gui" default="true"/>
  <arg name="rvizconfig" default="$(find fish_robot_description)/launch/urdf.rviz"/>
  <param name="robot_description" command="$(find xacro)/xacro $(arg model)"/>
  <param name="use_gui" value="$(arg gui)"/>
  <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher"/>
  <node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher"/>
  <node name="rviz" pkg="rviz" args="-d $(arg rvizconfig)" type="rviz" required="true"/>
</launch>

続いてROS 2でRviz2を起動するXMLを記載します。

dispaly.launch.xml
<?xml version='1.0' ?>

<launch>
    <!-- Define arguments -->
    <arg name="x" default="3.0" />
    <arg name="y" default="-1.0" />
    <arg name="z" default="1.0" />
    <arg name="roll" default="0"/>
    <arg name="pitch" default="0"/>
    <arg name="yaw" default="0" />
    <arg name="use_gui" default="true"/>

    <arg name="robot_name" default="fish_robot" />
    <arg name="description_pkg_name" default="fish_robot_description" />
    <arg name="xacro_file_path" default="$(find-pkg-share $(var description_pkg_name))/urdf/fish_robot.xacro" />
    <arg name="robot_description" default="$(command 'xacro $(var xacro_file_path)')"/>
    <arg name="rviz_config_path"
         default="$(find-pkg-share $(var description_pkg_name))/rviz/urdf.rviz" />
         
    <!-- Launch URDF -->
    <node pkg="robot_state_publisher" exec="robot_state_publisher" output="screen">
        <param name="robot_description" value="$(var robot_description)"/>
    </node>

    <node pkg="rviz2" exec="rviz2" args="-d $(var rviz_config_path)">
        <param name="robot_description" value="$(var robot_description)"/>
    </node>

    <node pkg="joint_state_publisher" exec="joint_state_publisher">
        <param name="source_list" value="[robot_joint_states, joint_state_broadcaster/joint_states]"/>
    </node>

    <group if="$(var use_gui)">
        <node pkg="joint_state_publisher_gui" exec="joint_state_publisher_gui" name="joint_state_publisher_gui" output="screen">
	    <remap from="joint_states" to="robot_joint_states"/>
        </node>
    </group>
</launch>

ROS 1からROS 2に移植する際の変更点は大きく以下となります。

  • パラメータ渡しが$(arg xxxxx) → $(var xxx)と変更
  • nodeタグ内でtypeが使用できず、nodeタグ内で別途paramタグを使用する ※1
  • $(find pkg_name)/xxx → $(find-pkg-share xxx)/xxxと変更

※1について、以下のような形でparamを宣言します。

公式ドキュメントにもtype, textfile, binfile, executableコマンドはROS 2ではサポートしていないという記載があります。

display.launch
-<!-- ROS 1 -->
-<node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher"/>

+<!-- ROS 2 -->
+<node pkg="robot_state_publisher" exec="robot_state_publisher" output="screen">
+    <param name="robot_description" value="$(var robot_description)"/>
+</node>

XML launchでGazeboを起動する

続いて、GazeboのlaunchもXMLで起動してみましょう。

まずはROS 1でGazeboを起動するXMLを記載しておきます。

gazebo.launch
<launch>
  <param name="robot_description" command="$(find xacro)/xacro $(find fish_robot_description)/urdf/fish_robot.xacro"/>
  <node name="spawn_urdf" pkg="gazebo_ros" type="spawn_model" args="-param robot_description -urdf -model fish_robot"/>
  <include file="$(find gazebo_ros)/launch/empty_world.launch">
    <arg name="paused" value="true"/>
    <arg name="use_sim_time" value="true"/>
    <arg name="gui" value="true"/>
    <arg name="headless" value="false"/>
    <arg name="debug" value="false"/>
  </include>
</launch>

続いてROS 2でGazeboを起動するXMLを記載します。

gazebo.launch.xml
<?xml version='1.0' ?>

<launch>
    <arg name="robot_name" default="fish_robot" />
    <arg name="description_pkg_name" default="fish_robot_description" />
    <arg name="gazebo_pkg_name" default="fish_robot_gazebo" />
    <arg name="xacro_file_path" default="$(find-pkg-share $(var description_pkg_name))/urdf/fish_robot.xacro" />
    <arg name="robot_description" default="$(command 'xacro $(var xacro_file_path)')"/>
    <arg name="rviz_config_path"
         default="$(find-pkg-share $(var description_pkg_name))/rviz/urdf.rviz" />

    <arg name="use_sim_time" default="true"/>
    <arg name="world_file_path" default="$(find-pkg-share $(var gazebo_pkg_name))/worlds/basic.world"/>

    <!-- gzserver -->
    <include file="$(find-pkg-share gazebo_ros)/launch/gzserver.launch.py">
        <arg name="use_sim_time" value="$(var use_sim_time)"/>
        <arg name="world" value="$(var world_file_path)"/>
    </include>
    <!-- gzclient -->
    <include file="$(find-pkg-share gazebo_ros)/launch/gzclient.launch.py">
        <arg name="use_sim_time" value="$(var use_sim_time)"/>
    </include>
    <!-- robot_state_publisher -->
    <node pkg="robot_state_publisher" exec="robot_state_publisher">
        <param name="use_sim_time" value="$(var use_sim_time)"/>
        <param name="robot_description" value="$(command 'xacro $(var xacro_file_path)')"/>
    </node>
    <!-- spawn_entity -->
    <node pkg="gazebo_ros" exec="spawn_entity.py" args="-entity $(var robot_name) -topic /robot_description">
        <param name="use_sim_time" value="$(var use_sim_time)"/>
    </node>
</launch>

GazeboをXMLで起動する際に大きく違う点は

gazebo.launch.xml
    <!-- gzserver -->
    <include file="$(find-pkg-share gazebo_ros)/launch/gzserver.launch.py">
        <arg name="use_sim_time" value="$(var use_sim_time)"/>
        <arg name="world" value="$(var world_file_path)"/>
    </include>
    <!-- gzclient -->
    <include file="$(find-pkg-share gazebo_ros)/launch/gzclient.launch.py">
        <arg name="use_sim_time" value="$(var use_sim_time)"/>
    </include>

のgzserver, gzclientの起動箇所でしょうか。

他の記述方法もあるのかもしれませんが、見つけた中ではこの書き方で起動できたので、こちらを使用しています。

他は、ROS 1からROS 2へ移植する際の変更点が変わっているという形です。

上記を実際に動かしてみると

https://twitter.com/tasada038/status/1688138658917109761

という感じで、XMLでRviz2やGazeboを起動することができます。

YAML launchでRviz2を起動する

launch.yamlでRviz2のconfigとノードを実行させてみます。

data_publisher.launch.yaml
launch:
  - let:
      name: model_name
      value: topic_view

  - arg:
      name: rviz_config
      default: $(find-pkg-share ros2_topic_sample)/rviz/$(var model_name).rviz
  - arg:
      name: use_sim
      default: "false"
  - arg:
      name: use_rviz
      default: "true"

  - node:
      pkg: rviz2
      exec: rviz2
      if: $(var use_rviz)
      args: -d $(var rviz_config)

  - node:
      pkg: ros2_topic_sample
      exec: diagnostic_pub
      name: diagnostic_node
      output: screen
  - node:
      pkg: ros2_topic_sample
      exec: float32_pub
      name: float32_node
      output: screen

launch.yamlの動作確認

https://twitter.com/tasada038/status/1781693040538919189

以上、皆さんのお力添えになれば幸いです。
Likeいただけると大変励みになりますので、よろしくお願いいたします。

References

Github: ros-industrial/industrial_training

manelpuig/ROS2_rUBot_ws

KBKN-Autonomous-Robotics-Lab/orange_ros2

Discussion