とてもつらいので、その気持ちをROS2のrqtプラグインに込めました。
どうも つらい と雷 です。
ROS2で動くrqtのプラグインを作りました。作り方を説明します。
GitHubにも公開してます。
目次
つらいときはrqtのプラグインを作ろう
つらいね
つらいけど動作環境を教えるよ
- Ubuntu 18.04
- ROS 2 Dashing
- ワークスペースは
~/ros2_ws
です rqt
コマンドでrqtが起動する状態です- Qt 5 Designer
- rqtプラグインのUIを作るとても重要なツールです
- 申し訳ありませんが、インストール方法を忘れました
- つらいけどググってください
- 参考までに、
/usr/lib/qt5/bin/designer
を実行してます - ごめんね
つらいけど空のパッケージつくるよ
まず、空のパッケージを作ります。名前はrqt_tsurai
です。
cd ~/ros2_ws/src ros2 pkg create --build-type ament_cmake rqt_tsurai
とりあえずビルドします。
cd ~/ros2_ws
colcon build
ビルドできたらオッケー。
パッケージを参考にするのもつらいね
すでに存在するROS2 で動くrqtプラグイン(パッケージ)を参考にします。
このパッケージはROS2で動くからいいね。羨ましい。起動してみよう。
rqt
起動したら Plugins -> Logging -> Console でrqt_consoleプラグインを選択します。
このプラグインは動いていいね。
コードを書くのはつらいので、だからコーディングはつらいと思います
それでは実装していきましょう。
最終的にどんなパッケージ構成になるのか
ros2 pkg create
直後はこのようになってます。
$ tree . ├── CMakeLists.txt ├── include │ └── rqt_tsurai ├── package.xml └── src
これを、以下のようにしていきます。include
ディレクトリは不要なので削除してください。
$ tree . ├── CMakeLists.txt ├── package.xml ├── plugin.xml ├── resource │ └── tsurai_widget.ui ├── scripts │ └── rqt_tsurai └── src └── rqt_tsurai ├── __init__.py ├── tsurai.py └── tsurai_widget.py
恐れることはありません。つらいけど順番に説明します。
UIの作成 tsurai_widget.ui
resource
ディレクトリを作成します。
mkdir resource
Qt 5 デザイナを起動します。Widgetテンプレートを選択して作成。
こんな画面が出ます。
プロパティを編集します。
objectNameをTsuraiWidgetに、windowTitleをTsuraiにします。
名前を付けて保存します。resouce
ディレクトリにtsurai_widget.ui
という名前で保存しましょう。
機能の実装 tsurai.py tsurai_widget.py
スクリプトファイルを作成します。つらいけどがんばりましょう。
src
以下にrqt_tsurai
ディレクトリを作り、その中に空のファイルを作成します。
cd src mkdir rqt_tsurai cd rqt_tsurai touch __init__.py touch tsurai.py touch tsurai_widget.py
つぎにtsurai_widget.py
を編集します。描画機能を担当するところです。つらいです。
コピペ推奨です。
# coding: UTF-8 import os from ament_index_python.resources import get_resource from python_qt_binding import loadUi from python_qt_binding.QtWidgets import QWidget from python_qt_binding.QtGui import QPainter, QFont from python_qt_binding.QtCore import Qt # クラス名は参照されるので書き間違えないように # Tusrai とか書くとつらいです class TsuraiWidget(QWidget): def __init__(self): super(TsuraiWidget, self).__init__() # パッケージ名も書き間違えないように pkg_name = 'rqt_tsurai' _, package_path = get_resource('packages', pkg_name) # UIをロードするけどファイル名を間違えないように ui_file = os.path.join( package_path, 'share', pkg_name, 'resource', 'tsurai_widget.ui') loadUi(ui_file, self) # オブジェクト名は間違えても動く?未調査 self.setObjectName('TsuraiWidget') # この関数が一定周期で呼び出される def paintEvent(self, event): painter = QPainter(self) # Hello world # ブラシ(塗りつぶし)の色を黒に painter.setBrush(Qt.black) # ペン(線描画)の色も黒に painter.setPen(Qt.black) # 背景を描く # self.rect()はwidgetのサイズを返すので、widget全体を埋める四角形を描画する # ペンとブラシの色が黒なので背景色は真っ黒 painter.drawRect(self.rect()) # ペン(線描画)の色を白にする painter.setPen(Qt.white) # フォントサイズを変更する font = painter.font() # つらさはできるだけ大きく表現したほうが良い # 周りが気づくように font.setPointSize(80) painter.setFont(font) # テキストを描画する x = 0 # 左端 y = self.rect().height()*0.5 # 上下の中心 painter.drawText(x,y, "TSU☆RA☆I")
つぎにtusrai,py
を編集します。
# coding: UTF-8 from qt_gui.plugin import Plugin from python_qt_binding.QtCore import QTimer from rqt_tsurai.tsurai_widget import TsuraiWidget # クラス名は参照されるので書き間違えないこと # Tusrai とか書くとつらいです class Tsurai(Plugin): def __init__(self, context): super(Tsurai, self).__init__(context) # オブジェクト名は間違えても動く?未調査 self.setObjectName('Tsurai') self._context = context # ここでTsuraiWdigetをセットしてつらくなろう self._widget = TsuraiWidget() if context.serial_number() > 1: self._widget.setWindowTitle( self._widget.windowTitle() + (' (%d)' % context.serial_number())) context.add_widget(self._widget) # TsuraiWidgetは一定周期で更新したいのでQTimerを使う self._timer = QTimer() self._timer.timeout.connect(self._widget.update) # 16 msec 周期で更新させる self._timer.start(16) def shutdown_plugin(self): # 終了時はタイマーを止める self._timer.stop() pass def save_settings(self, plugin_settings, instance_settings): # セーブ機能は何もしない # つらい気持ちをファイルに保存する機能 いる? pass def restore_settings(self, plugin_settings, instance_settings): # リストア機能は何もしない # つらい気持ちを復元してどうするの? pass
つらいスクリプトファイルの作成 rqt_tsurai
scripts
ディレクトリを作成して、そこにrqt_tsurai
ファイルを作成します。
mkdir scripts cd scripts touch rqt_tsurai
rqt_tsurai
を編集します。中身はPythonコードです。
#!/usr/bin/env python3 import sys from rqt_gui.main import Main main = Main() sys.exit(main.main(sys.argv, standalone='rqt_tsurai.tsurai.Tsurai'))
プラグインファイルの作成 plugin.xml
準備が整ったのでplugin.xml
を作成します。
<library path="src"> <!-- クラス名が重要なので書き間違えないように --> <class name="Tsurai" type="rqt_tsurai.tsurai.Tsurai" base_class_type="rqt_gui_py::Plugin"> <description> <!-- プラグインの説明です。 --> A Python GUI plugin for displaying TSURAI </description> <qtgui> <group> <!-- プラグインのグループを設定します --> <!-- rqtを起動したときにPluginsから選択するアレです --> <!-- さすがにLoggerではないのでVisualizationにしました --> <!-- すでにあるVisualizationのプラグイン(例えばImage Viewを)を参照するのがおすすめ --> <label>Visualization</label> <icon type="theme">folder</icon> <statustip>Plugins related to visualization.</statustip> </group> <!-- プラグインのラベルです。ちゃんとTsuraiって書こうね --> <label>Tsurai</label> <!-- プラグインのアイコンです。何でもいいと思います。 --> <!-- Image Viewと同じにしました。 --> <icon type="theme">image-x-generic</icon> <!-- プラグイン選択時にrqtウィンドウの1番下に表示される説明文です --> <statustip>A Python GUI plugin for displaying TSURAI</statustip> </qtgui> </class> </library>
CMakeLists.txt の編集
もう少しで完成です。つらいけどがんばりましょう。
パッケージがビルドできるように、CMakeLists.txtを編集します。
cmake_minimum_required(VERSION 3.5) project(rqt_tsurai) # Load ament and all dependencies required for this package find_package(ament_cmake REQUIRED) find_package(ament_cmake_python REQUIRED) ament_python_install_package(${PROJECT_NAME} PACKAGE_DIR src/${PROJECT_NAME}) install(FILES plugin.xml DESTINATION share/${PROJECT_NAME} ) install(DIRECTORY resource DESTINATION share/${PROJECT_NAME} ) install(PROGRAMS scripts/rqt_tsurai DESTINATION lib/${PROJECT_NAME} ) ament_package()
package.xmlの編集
最後にpackage.xml
を編集して、パッケージの説明や依存関係を書きましょう。
<?xml version="1.0"?> <?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?> <package format="3"> <name>rqt_tsurai</name> <version>0.0.0</version> <description>rqt_tsurai provides a GUI plugin for displaying TSURAI.</description> <maintainer email="hoge@hoge.com">akshota</maintainer> <license>MIT</license> <buildtool_depend>ament_cmake</buildtool_depend> <exec_depend>ament_index_python</exec_depend> <exec_depend version_gte="0.2.19">python_qt_binding</exec_depend> <exec_depend>rclpy</exec_depend> <exec_depend>rqt_gui</exec_depend> <exec_depend>rqt_gui_py</exec_depend> <exec_depend>rqt_py_common</exec_depend> <export> <!-- <architecture_independent/> --> <rqt_gui plugin="${prefix}/plugin.xml"/> <build_type>ament_cmake</build_type> </export> </package>
つらいパッケージのビルドと実行
つらさを乗り越えてパッケージができました。ビルドしましょう
cd ~ros2_ws
colcon build
セットアップファイルを読み込みます。読み込むファイルは使用しているシェルに合わせてください。
source ./install/setup.zsh
rqtを起動してTsuraiプラグインを読み込みます。rqtがプラグイン参照できるようにオプションを付けます。
# 新たにプラグインを作成した後は、オプションを付けてrqtを起動 rqt --force-discover
Plugins -> Visualization -> Tsuraiを選択します。Widgetが表示されたら成功です。
おわりに
rqtプラグインのチカラはこんなもんじゃありません。 ボタンとかスライダとか、UIを鍛えれば更に強くなれます。弱いのは僕です。
つらいけど、この記事をまとめます。