2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

rqt_guiでプラグインに引数をわたす仕組みを調べる

Last updated at Posted at 2020-01-02

はじめに

rqt_topicソースを眺めている時にselected_topicsがコンストラクタで設定できるように実装されていますが、rqt_gui経由では設定できなかったため、今回その仕組みを調べました。

前提条件

環境 バージョン
開発機 Ubuntu 16.04.6 LTS
ROS Kinetic Kame

rqt_guiで引数を設定する

ドキュメントには詳細がないため、まずヘルプを参照します。

$ python /opt/ros/kinetic/lib/rqt_gui/rqt_gui -h
usage: rqt_gui [-b BINDING] [--clear-config] [-f] [--force-discover] [-h] [-l]
               [-ht] [-p PERSPECTIVE] [--perspective-file PERSPECTIVE_FILE]
               [--reload-import] [-s PLUGIN] [-t] [-v]
               [--args [PLUGIN_ARGS [PLUGIN_ARGS ...]]] [--list-perspectives]
               [--list-plugins] [--command-pid PID]
               [--command-start-plugin PLUGIN]
               [--command-switch-perspective PERSPECTIVE]

Options for GUI instance:
  -b BINDING, --qt-binding BINDING
                        choose Qt bindings to be used [pyqt|pyside]
  --clear-config        clear the configuration (including all perspectives
                        and plugin settings)
  -f, --freeze-layout   freeze the layout of the GUI (prevent rearranging
                        widgets, disable undock/redock)
  --force-discover      force a rediscover of plugins
  -h, --help            show this help message and exit
  -l, --lock-perspective
                        lock the GUI to the used perspective (hide menu bar
                        and close buttons of plugins)
  -ht, --hide-title     hide the title label, the icon, and the help button
                        (combine with -l and -f to eliminate the entire title
                        bar and reclaim the space)
  -p PERSPECTIVE, --perspective PERSPECTIVE
                        start with this named perspective
  --perspective-file PERSPECTIVE_FILE
                        start with a perspective loaded from a file
  --reload-import       reload every imported module
  -s PLUGIN, --standalone PLUGIN
                        start only this plugin (implies -l). To pass arguments
                        to the plugin use --args
  -t, --on-top          set window mode to always on top
  -v, --verbose         output qDebug messages
  --args [PLUGIN_ARGS [PLUGIN_ARGS ...]]
                        arbitrary arguments which are passes to the plugin
                        (only with -s, --command-start-plugin or --embed-
                        plugin). It must be the last option since it collects
                        all following options.

Options to query information without starting a GUI instance:
  These options can be used to query information about valid arguments for
  various options.

  --list-perspectives   list available perspectives
  --list-plugins        list available plugins

Options to operate on a running GUI instance:
  These options can be used to perform actions on a running GUI instance.

  --command-pid PID     pid of the GUI instance to operate on, defaults to
                        oldest running GUI instance
  --command-start-plugin PLUGIN
                        start plugin
  --command-switch-perspective PERSPECTIVE
                        switch perspective

Special options for embedding widgets from separate processes:
  These options should never be used on the CLI but only from the GUI code
  itself.

rqt_guiでプラグインに渡す引数は、rqt_gui -s {プラグイン名} --args {引数}となるようです。ただし注意点としてIt must be the last option since it collects all following options.とあるように、このオプションは、全てのそれ以降の引数を対象としているため、最後の引数とする必要があります。

rqt_topicの場合

rqt_topicselected_topicsを設定します。

$ python /opt/ros/kinetic/lib/rqt_gui/rqt_gui -s rqt_topic --args /rosout

しかし選択したトピック以外にも表示がされてしまいます。

image.png

rqt_plotの場合

rqt_plotに対象のトピックを設定します。

$ python /opt/ros/kinetic/lib/rqt_gui/rqt_gui -s rqt_plot --args /my_controller/cmd_vel/linear

image.png

このプラグインでは、意図した引数として設定できていることが確認できます。そのため、引数の設定方法は間違っていないようです。

rqt_guiの仕組みを調べる

rqt_guiを実行するとコンストラクタが呼ばれ、superに渡ります。これは、from qt_gui.main import Main as Baseで定義されており、Baseのコンストラクタが呼ばれます。初期化が終わるとmain.main()からsuper(Main, self).mainが呼ばれ、mainが実行されます。mainを実行するとargvは、argumentsに格納されます。

main.py#L224でstandaloneでないときの処理分岐がありますが、今回はstandalone=NoneのためTrueになり、plugin_argsが設定され、最終的にself._options.plugin_argsに設定されます。

コマンドラインから-sオプションで設定したプラグインパラメータは、standaloneがfalseの時にmain.py#L112standalone_pluginに設定され、pluginに格納され、plugin_managerによってロードされます。

load_pluginでは、argvという変数になり、内部のself._load_plugin_loadを呼び出します。今回は、 direct handler for in-process pluginsになるためPluginHandlerDirecthandlerを設定します。PluginHandlerDirectは、PluginHandlerを継承しているため、super(PluginHandlerDirect, self)でargvが設定され、self._argvに格納されます。最後にhandlerでloadが実行されます。

loadが実行されるとself._contextPluginContextが生成され、self._handlerとして設定されるため、argvでhundlerのargvを参照することができます。PluginHandlerのロードが行われると、self._loadが呼ばれますが、これはNotImplementedErrorからわかる通りhandlerによってオーバライドされるものです。実装は、plugin_handler_direct.py#L54となり、self._context(先ほど設定したPluginContext)がロードに使用されていることが確認できました。

プラグイン側の実装の確認

rqt_guiでcontextという形でプラグイン側に渡されることがわかりました。それでは、前述でパラメータの設定の確認ができたrqt_plotの実装を確認してみます。

rqt_plotの引数について

コンストラクタのcontextが、前述のPluginContextで設定したものであり、parse_argsによってargvがパースされます。parse_argsは、Plot.add_argumentsとなり、rqt_guiで設定した引数がプラグインまで実際にわたされていることが確認できました。

rqt_topicの引数について

では、引数を設定しても反映されなかったrqt_topicについて確認してみます。contextは、同様ですが、実装を確認するとcontextからargvを呼び出している部分がありません。同様にこのプラグインにはargparseの実装がありません。つまり、コンストラクタにはselected_topicsを設定すればできるように実装されているだけでインターフェースが存在しませんでした。これが、今回引数を設定しても反映されない原因でした。

おまけ

今回の調査では、rqt_guiを経由した非スタンドアロンで起動しましたが、スタンドアロンもそれぞれ用意されています。コマンドとして登録されているものは、下記のみですが、

$ which rqt_plot
/opt/ros/kinetic/bin/rqt_plot
$ ls /opt/ros/kinetic/bin/rqt* | grep rqt
-rwxr-xr-x 1 root root 255 6月 8 2019 /opt/ros/kinetic/bin/rqt
-rwxr-xr-x 1 root root 229 6月 8 2019 /opt/ros/kinetic/bin/rqt_bag
-rwxr-xr-x 1 root root 148 6月 8 2019 /opt/ros/kinetic/bin/rqt_console
-rwxr-xr-x 1 root root 156 6月 8 2019 /opt/ros/kinetic/bin/rqt_dep
-rwxr-xr-x 1 root root 149 6月 8 2019 /opt/ros/kinetic/bin/rqt_graph
-rwxr-xr-x 1 root root 162 6月 8 2019 /opt/ros/kinetic/bin/rqt_logger_level
-rwxr-xr-x 1 root root 236 6月 8 2019 /opt/ros/kinetic/bin/rqt_plot
-rwxr-xr-x 1 root root 243 6月 8 2019 /opt/ros/kinetic/bin/rqt_shell

standaloneの実行は、

$ ls /opt/ros/kinetic/lib/rqt* | grep -v / | grep -v '^\s*$'
rqt_bag
rqt_console
rqt_controller_manager
rqt_dep
rqt_graph
rqt_gui
rqt_joint_trajectory_controller
rqt_launch
rqt_logger_level
rqt_moveit
rqt_msg
rqt_nav_view
rqt_plot
rqt_pose_view
rqt_publisher
rqt_py_console
rqt_reconfigure
rqt_robot_monitor
rqt_robot_steering
rqt_runtime_monitor
rqt_rviz
rqt_service_caller
rqt_shell
rqt_srv
rqt_tf_tree
rqt_top
rqt_topic
rqt_web

から実行することができます。これらの違いは、rqt_topic/setup.pyrqt_plot/setup.pyからなるもので、generate_distutils_setupscriptsという引数を渡すかどうかの違いです。これは、setup_dot_py.html#using-package-xml-in-setup-py

ROS Users should generally not use the scripts argument, as in ROS, executables should be executed using rosrun rather than being installed to the global bin folder.

よりわかる通りscripts引数を使うとROS Global Binにインストールされます。これは、catkinで設定されるCATKIN_GLOBAL_BIN_DESTINATIONのことです。setup.pyを使用したcatkin_python_setupがあった場合、インストールの挙動がCMakeLists.txtだけで完結しないので注意が必要です。

話を戻すと実装は、rqt_topicrqt_plotで確認でき、これまでのソースの確認ですでにわかる通り、standalone=pluginでスタンドアローンで起動し、plugin_argument_provider=Plot.add_argumentsでプラグインのパーサを設定していることがわかります。

まとめ

  • rqt_guiプラグインでの引数の扱い方を確認できた
  • プラグインで引数を扱うためにはcontextからargvを参照すると共にargparseの実装が必要である
  • インストールは、CMakeLists.txtで完結せずsetup.pyで追加の設定が可能である
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?