こんにちは!長谷川です。
前回はCRANE+の状態をモデルに反映させる方法について説明しましたが、今回は、CRANE+の状態をrviz上でモニタリングしつつ、CRANE+を自動で動かす方法について説明したいと思います。
使用するプログラム
実は、今回やろうとしていることは、すでに勉強したことの組み合わせで実現できます。
CRANE+を自動で動かすプログラムは第6回目の記事で作成済みですし、CRANE+の状態をrvizに反映させるプログラムも第10回目の記事で作成済みです。それぞれのプログラムで立ち上げられるノード名、関係するトピックは異なっているので、これら2つのプログラムを同時に起動できれば、目的を達成できることになります。
launchファイルの利便性
今まで勉強してきたことを組み合わせると、今回は以下のような手続きをすればいいことになります。
1: CRANE+とPCを接続
2: 「sudo chmod 6666 /dev/ttyUSB0」と端末に入力
3: 「roslaunch my_dynamixel_tutorial controller_manager.launch」と入力
4: 新しい端末を開き、「roslaunch roslaunch my_dynamixel_tutorial start_tilt_controller.launch」と入力
5: crane_urdf/srcに移動し、「roslaunch crane_urdf display.launch model:=crane.urdf」と入力
6: 新しい端末を開き、「rosrun crane_urdf reflect_crane_in_rviz」と入力
7: 新しい端末を開き、「rosrun turtlebot_arm turtlebot_arm」と入力
・・・面倒ですね。この面倒な作業を軽減するため、新たなlaunchファイルを作ることにします。これにより、少なくとも5〜7までの手順をコマンド1回で行うことができるようになります。プログラムの方に多少手を加えれば、3〜7までの作業をコマンド1回でできるようになります。
ROSのlaunchファイルについて
前回、display.launchというlaunchファイルを作りましたが、この時にはlaunchファイルについて詳しく説明しませんでした。今回は、display.launchについても詳しく説明しつつ、新しいlaunchファイルを作っていこうと思います。
launchファイルとは、様々なプログラムを組み合わせ、複数のノードを同時に立ち上げることができるファイルです。「roslaunch」というコマンドは、このlaunchファイルを起動するためのものだった、というわけです。このファイルに書いておけば、立ち上げたい全てのノードを1回のコマンドで立ち上げることができます。いちいち「rosrun」する必要がなくなるのです。しかもこのlaunchファイル、内部で他のlaunchファイルも実行することができます。また、それぞれのプログラムに対するパラメータも、ファイル内で決めておくことができるのです。このような機能により、操作がとても楽になります。それだけでなく、プログラムを別個の処理ごとに分けることが容易になるので、モジュール化と再利用性の向上を図ることができるのです。今回の場合では、CRANE+を動かすプログラムとCRANE+の状態をrvizに反映させるプログラムは独立に動いているので、CRANE+の動かし方を変えたいときは、CRANE+を動かすプログラムのみ変更すればいいという事になります。
新しいlaunchファイルの作成
例のごとく解説は後回しにして、まずはlaunchファイルを作ってしまいましょう。
端末に、
$ roscd crane_urdf/src $ vi auto_crane_rviz.launch
と入力します。以下を貼り付けます。
<launch> <param name="robot_description" textfile="$(find crane_urdf)/src/crane.urdf" /> <param name="use_gui" value="False"/> <rosparam param="source_list">["joint_states_source"]</rosparam> <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" /> <node name="robot_state_publisher" pkg="robot_state_publisher" type="state_publisher" /> <node name="rviz" pkg="rviz" type="rviz" args="-d $(find urdf_tutorial)/urdf.rviz" required="true" /> <node name="reflect_crane_in_rviz" pkg="crane_urdf" type="reflect_crane_in_rviz" /> <node name="turtlebot_arm" pkg="turtlebot_arm" type="turtlebot_arm" /> </launch>
貼り付けたら、保存してviを終了してください。これで、新しいlaunchファイルが完成です。
実行
早速、新しいlaunchファイルを実行してみましょう。
第5回目の記事にしたがって、CRANE+とPCを接続し、「roslaunch my_dynamixel_tutorial start_tilt_controller.launch」まで入力してください。これで、1〜4までの手続きが終わりました。その後、端末に、
roslaunch crane_urdf auto_crane_rviz.launch
と入力します。これで、CRANE+も動き始め、rvizも起動すると思います。天板上で動くので、天板にPC等を置くのは危険です。
launchファイルの解説
auto_crane_rviz.launchを見ながら、launchファイルの書き方について学びましょう。
<launch>
</launch>
この2つで囲まれた部分が、launchファイルとして認識されます。
<param name="robot_description" textfile="$(find crane_urdf)/src/crane.urdf" />
ここでは、robot_descriptionというパラメータに、crane_urdfパッケージのsrcディレクトリ内にあるcrane.urdfファイルを設定します。パラメータというのは、変数のことです。パラメータサーバというパラメータを共有できる仕組みがあって、ノードがそこで定義されたパラメータを読み込んで動作に反映させています。このパラメータをノードの外から変更することで、ノードの設定を変えることができます。
こちらとこちらを読むと、robot_descriptionというのは、joint_state_publisherとrobot_state_publisherにおいて、ロボットのURDFデータを格納するパラメータのようです。ここに、第8回目の記事で作成したcrane.urdfを設定することで、モデルを読み込ませます。
<param name="use_gui" value="False"/>
先ほど紹介したページを読むと、use_guiというのは、joint_state_publisherにおいて、各関節の値をスライドバーで変更できるウィンドウを出すかどうかを決めるパラメータのようです。ここにFalseという値を設定することで、ウィンドウを出さない設定にします。なお、前の行ではパラメータ名を指定した後、「textfile=」と書いていましたが、これはファイルの中身をパラメータに設定するためのコマンドです。この行では、値を直接設定するため、「value=」と書いています。
<rosparam param="source_list">["joint_states_source"]</rosparam>
rosparamタグは、先ほど使ったparamタグに似ています。paramは主にひとつずつパラメータを設定しますが、rosparamはyamlファイルという、パラメータをまとめてあるファイルを読み込んで、複数のパラメータを一度に設定することが可能です。この行では、yamlファイルを読み込んでいるわけではなく、source_listという一つのパラメータしか設定していません。ですが、source_listには文字列のリスト型を設定しなくてはならず、paramタグではリスト型を設定できるのかよくわからないため、rosparamタグを使用しました。なおリスト型というのは、例えば[3, 4]のように値を並べたものです。source_listパラメータの働きについては、前回説明しましたので、割愛します。
<node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" />
ここではノードを立ち上げています。「name=”joint_state_publisher”」で、立ち上げるノード名をjoint_state_publisherとし、「pkg=”joint_state_publisher”」でノードの動作が書かれた実行ファイルはjoint_state_publisherパッケージにあると宣言します。次に、「type=”joint_state_publisher”」で、joint_state_publisherが実行するファイルであると宣言します。以上の項目が、ノードを立ち上げるために必要な最低限の宣言です。
<node name="rviz" pkg="rviz" type="rviz" args="-d $(find urdf_tutorial)/urdf.rviz" required="true" />
ここもノードを立ち上げる文ですが、いくつかオプションが付け加えられています。「args」というのは、ノードに渡す引数です。端末上でプログラムを起動するとき、コマンドライン上で引数を渡すことができますが、あれと同じようなものですね。「required」というのは、ノードが停止した時にroslaunchを停止させるかどうかを設定できます。ここに「true」を設定しているので、rvizノードが停止すると、roslaunch全体が停止します。
これで、auto_crane_rviz.launchで何が行われていたかは大体説明できたと思います。launchファイルについてもっと詳しく勉強したい方は、こちらをご覧ください。で、読んでいくと、includeタグなるものがあります。これは、launchファイル内で他のlaunchファイルを実行するためのタグです。これを使うと、「roslaunch my_dynamixel_tutorial controller_manager.launch」と「roslaunch roslaunch my_dynamixel_tutorial start_tilt_controller.launch」もauto_crane_rviz.launch内で実行することができます。この場合、以下のように書けばOKです。
<launch> <param name="robot_description" textfile="$(find crane_urdf)/src/crane.urdf" /> <param name="use_gui" value="False"/> <rosparam param="source_list">["joint_states_source"]</rosparam> <include file="$(find my_dynamixel_tutorial)/controller_manager.launch" /> <include file="$(find my_dynamixel_tutorial)/start_tilt_controller.launch" /> <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" /> <node name="robot_state_publisher" pkg="robot_state_publisher" type="state_publisher" /> <node name="rviz" pkg="rviz" type="rviz" args="-d $(find urdf_tutorial)/urdf.rviz" required="true" /> <node name="reflect_crane_in_rviz" pkg="crane_urdf" type="reflect_crane_in_rviz" /> <node name="turtlebot_arm" pkg="turtlebot_arm" type="turtlebot_arm" /> </launch>
ところが、これだと起動当初にCRANE+が暴走します。なぜかというと、controller_manager.launchやstart_tilt_controller.launchの処理が終わっていない状態、つまり初期設定ができていない状態で他のプログラムが走りだすからです。これを解決するためには、reflect_crane_in_rviz.cppやturtlebot_arm.cppの最初にwaitを入れてやればいいです。または、ROSだけに頼らず、シェルスクリプトを使うという手もありますが、今回は割愛したいと思います。
以上、CRANE+の状態をrviz上でモニタリングしつつ、CRANE+を自動で動かす方法について説明しました。
とりあえず、CRANE+とROSの組み合わせでできることの基本は解説できたと思いますので、今回でCRANE+の連載は終わりにしたいと思います。ここまでお読み下さり、ありがとうございました。