## For instruction on writing tutorials ## http://www.ros.org/wiki/WritingTutorials #################################### ##FILL ME IN #################################### ## for a custom note with links: ## note = This tutorial assumes you are comfortable with using [[rospy]], and have gone through the [[ROS/Tutorials/CreatingPackage]] and [[ROS/Tutorials/WritingPublisherSubscriber(python)]]. Also assumes you already have QWidget-based GUI that you want to integrate into ROS by using rqt ## for the canned note of "This tutorial assumes that you have completed the previous tutorials:" just add the links ## note.0= ## descriptive title for the tutorial ## title = Create your rqt plugin package ## multi-line description to be displayed in search ## description = Entry point for creating your rqt plugin either in python or C++. ## the next tutorial description (optional) ## next = ## links to next tutorial (optional) ## next.0.link= [[rqt/Tutorials/Writing a Python Plugin]] ## next.1.link= [[rqt/Tutorials/Writing a C++ Plugin]] ## what level user is this tutorial for ## level= BeginnerCategory ## keywords = #################################### <> <> <> == Intro == This tutorial will show you how to create a plugin to integrate your custom user interface into ROS' GUI framework [[rqt]]. When you want to run your code after writing it, refer to [[rqt/UserGuide]] about how to run and so on. A complete set of all files in this tutorial using python is available on[[https://github.com/lucasw/rqt_mypkg|github]]. These [[https://github.com/ros-visualization/rqt_common_plugins|rqt plugins]] are also useful because they bring up than an empty widget. For example [[https://github.com/ros-visualization/rqt_common_plugins/tree/groovy-devel/rqt_bag|rqt_bag]]. Refer to the [[http://wiki.osrfoundation.org/Usability|Usability Resources]] for design guidelines. == Prerequisite & assumption == * [[rqt/UserGuide#Installation|rqt installed]]. * Have QWidget-based GUI that you want to integrate into ROS by using rqt. * Assumes ROS [[groovy]] or later, and [[catkin]] as a buildsystem by default. * For `fuerte`, [[http://answers.ros.org/question/65679/install-rqt-plugin-with-rosbuild/?answer=65773#post-id-65773|this thread]] might be of your help. * This tutorial is written based on Ubuntu 12.10 (initiated on 3/12/2013) * (!) Examples in this page use `python`. With `C++`, replace `rqt_gui_py` with `rqt_gui_cpp` == Steps to create rqt plugin pkg == === Create an Empty Package === Before getting started, let's create an empty package to called `rqt_mypkg`, somewhere in your package path.: {{{{#!wiki buildsystem rosbuild {{{ roscreate-pkg rqt_mypkg rospy rqt_gui rqt_gui_py }}} }}}} {{{{#!wiki buildsystem catkin {{{ catkin_create_pkg rqt_mypkg rospy rqt_gui rqt_gui_py }}} }}}} === Modify package.xml === ==== Add export tag ==== So your plugin can be discovered, you must declare the plugin in either [[catkin/package.xml|package.xml]] for [[catkin]], or [[Manifest|manifest.xml]] for [[rosbuild]]: {{{#!xml : : }}} [[https://github.com/ros-visualization/rqt_common_plugins/blob/groovy-devel/rqt_bag/package.xml|Complete `package.xml` example]]. ==== Remove build_depend (Optional) ==== If you're writing your plugin in `python` that doesn't require building, you can omit [[catkin/Tutorials/CreatingPackage#ROS.2BAC8-Tutorials.2BAC8-catkin.2BAC8-CreatingPackage.dependencies_tags|build_depend]] tags. === Create plugin.xml file === Then you create the referenced file `plugin.xml` with additional meta information regarding the plugin: {{{#!xml An example Python GUI plugin to create a great user interface. system-help Great user interface to provide real value. }}} Consider the [[rqt/Plugins|available plugins]] and their grouping when deciding where to place your plugin. [[https://github.com/ros-visualization/rqt_common_plugins/blob/groovy-devel/rqt_bag/plugin.xml|Complete example]]. ==== Attributes of library element in plugin.xml ==== Usually you can just copy the example and modify wherever you feel necessary to get the plugin to work. Here are some explanations about xml attributes of the `library` element for those who need to know more. `/library@path` . The package-relative path which gets added to sys.path. `/library/class@name` . The name of the plugin, which must be unique within a package. `/library/class@type` . The concatenated name of the package, module and class, which is used for the import statement. (Form: package.module.class) `/library/class@base_class_type` . For Python plugins which use the rospy client library the value is `rqt_gui_py::Plugin`. `/library/description` . The description of the plugin. `/library/qtgui` . This tag contains additional optional information about the package. If none are provided, the name of the plugin is used as the label for the plugin in the menu and the description is displayed as a status tip. `/library/qtgui/group` (optional, multiple) . Enables grouping of plugins. Group tags can contain a `label`, `icon` and `statustip` tag. The groups form a hierarchy of menus where the plugin is added as the leaf. The groups of different plugins are merged based on their label (icons and statustip may be overridden by other plugins when they are defined differently). `/library/qtgui/label` . Overrides the label with which the plugin appears in the menu. `/library/qtgui/icon` . Defines the icon that should be shown beside the label (depending on the type of attribute). `/library/qtgui/icon@type` * `file` (default): the icon value is a package-relative path to an image. * `theme`: the icon value names an icon defined by the [[http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html|Icon Naming Specification]]. * `resource`: the icon value names a Qt resource. `/library/qtgui/statustip` . Overrides the status tip that is shown when hovering over the plugin label. == Write a plugin code == Writing code is explained on separate pages for [[rqt/Tutorials/Writing a Python Plugin|python]] | [[rqt/Tutorials/Writing a C++ Plugin|C++]] respectively. === Coding rule for rqt === * Mostly follow the general ROS coding style guide [[CppStyleGuide|C++]] | [[PyStyleGuide|Python]] * List dependency, import in an alphabetical order * rqt in python [[rqt/Tutorials/Writing a Python Plugin#python_coding_style_for_rqt|defines some rules]] Also, `python` in `rqt` defines documenting rules [[rqt/Tutorials/Writing a Python Plugin#python_coding_style_for_rqt|here]]. === Choice of programming language in rqt === Mainly because of the ease of maitainance, many `rqt` plugins are written in `python`, and it is strongly '''recommended for new plugins to be written in `python`'''. `C++` is completely acceptable in `rqt`. Only if: * you need the extra performance of C++ or want to access libraries only available in C++ (i.e. [[rqt_image_view]]) * you are far more comfortable with `C++` than `Python` You can find out in which language the existing `rqt plugin`s are written at [[rqt/Plugins]] page. Go to the page of each plugin and find its source repository where you can look at the source code. == Install & Run your plugin == See the [[rqt/UserGuide#Running_rqt|Running rqt]] section for how to run your plugin. {{{{#!wiki buildsystem catkin With `catkin`, no matter which method in the link above you want to run your plugin, you need to install it via `CMake` which puts the script into a package-specific folder which is not on the `PATH`. Add macros to your `setup.py` [[http://answers.ros.org/question/50661/catkin-setuppy-installation-into-devel-space-not-working/|(reference)]]. For example, after adding the line the section that contains it might look like : {{{ from distutils.core import setup from catkin_pkg.python_setup import generate_distutils_setup d = generate_distutils_setup( packages=['rqt_mypkg'], package_dir={'': 'src'}, ) setup(**d) }}} Also make sure in your [[catkin/CMakeLists.txt|CMakeLists.txt]], to uncomment a line: {{{ catkin_python_setup() }}} Add `install` macro that puts the script into a location where it is rosrun-able is declared. For example: {{{ install(PROGRAMS scripts/rqt_mypkg DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} ) }}} Add the following lines to call the resource and plugin.xml {{{ install(DIRECTORY resource DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} ) install(FILES plugin.xml DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} ) }}} These scripts can be run by: {{{ $ rosrun rqt_mypkg rqt_mypkg }}} }}}} {{{#!wiki buildsystem rosbuild Detail for rosbuild is TBD. Ask maintainers if you need to know immediately, or feel free to modify this wiki once you figure it out.. A very short description how to install your plugin in fuerte (because catkin does not work very well in fuerte) can be found at: [[http://answers.ros.org/question/65679/install-rqt-plugin-with-rosbuild/?answer=65773#post-id-65773]] }}} If your plugin does not show up under the `Plugins` menu when you launch rqt, you may need to run: {{{ rqt --force-discover }}} == Option == * Do not forget to add enough info into `package.xml`, just as with every `ROS` package. === Unit testing rqt plugins === Needless to say, making & maintaining `unit test` codes is strongly recommended, but not required. * Unit test codes can be best stored under `/test` folder on the root directory of a package. * Area covered by unit testing can only be business & application logic. There seems to be no convenient way to do unit test for visual components ([[http://www.theregister.co.uk/2007/10/22/gui_unit_testing/|ref]]). * If you have better idea, please open a discussion in [[http://ros.org/wiki/rqt/#Community|rqt community]]. This is very interesting topic. * For integrated test, using [[rosunit]] is highly recommended. === To run your plugin directly === You can add your `rqt` plugin to the system `PATH` so that you can run it on-the-fly without using other tools such as `rosrun`, `rqt_gui` and so on. It is not, however, recommended to put it to `PATH` in order to keep system common space cleaner. Only if you dare to do so, there's a way. {{{{#!wiki buildsystem catkin Running custom `rqt` plugins directly is NOT recommended (discussion [[https://github.com/ros-visualization/rqt_common_plugins/issues/1#issuecomment-11919157|1]], [[https://groups.google.com/d/msg/ros-sig-rqt/QkqYjMJ0dZk/A9R7FPdsFpEJ|2]], [[https://groups.google.com/d/msg/ros-sig-rqt/lIvOLIChRzo/3tccjWJ_0yMJ|3]]). Do this only when you're really in need. Add 1 line: {{{ scripts=['%RELATIVE_PATH_TOYOUR_EXECUTABLE%']}}} to your `setup.py` [[http://answers.ros.org/question/50661/catkin-setuppy-installation-into-devel-space-not-working/|(reference)]]. For example after adding the line the section that contains it might look like : {{{ d = generate_distutils_setup( packages=['rqt_mypkg'], package_dir={'': 'src'}, scripts=['scripts/rqt_mypkg'] ) }}} Once you're done, run: {{{ $ cd %TOPDIR_YOUR_CATKIN_WS% $ catkin_make }}} This will yield a relay script to `%TOPDIR_YOUR_CATKIN_WS%devel/bin`, which you can call if you're already sourced `%TOPDIR_YOUR_CATKIN_WS%devel/setup.bash%` (or similar, as you wish). }}}} {{{#!wiki buildsystem rosbuild This is not fully supported with [[rosbuild]]. }}} === Practices to follow on making rqt plugins === * Same as general GUI development, you should pay attention to from which thread you're updating GUI. * Although nodes that are instantiated from `rqt` plugins run as different thread in the same process, callback function that is given to node handler (`NodeHandle` in `C++` / `rospy`.`Subscriber` (for example)) runs in the main thread, which enables to update GUI from there. * Apply common GUI software architecture (eg. [[http://en.wikipedia.org/wiki/Model–view–controller|MVC]]) * For the same reason, you should ideally separate `Plugin` class (`rqt_gui_cpp::Plugin` or `rqt_gui_py.plugin.Plugin`) and your widgets' implementation. ## AUTOGENERATED DO NOT DELETE ## TutorialCategory ## FILL IN THE STACK TUTORIAL CATEGORY HERE