環境
本記事は以下の環境を想定して記述している。
項目 | 値 |
---|---|
OS | Ubuntu 22.04 |
ROS | ROS 2 Humble |
Qt | Qt5.15.3 |
概要
Qtで作成したGUIとROS 2のPub&Sub通信を組み合わせて、GUI操作によりトピックをpublishするノードと、トピックをsubscribeしてGUIに表示するノードを作成する。実際に作成したノードを起動して、QtとROS 2の処理が組み合わされて動作することを確認する。
このページは、ROS講座94 Qtでpub・subするの内容をROS 2対応させたものである。
前準備
前提条件
このチュートリアルの実施前に、次の環境を準備すること。
-
実習ROS 2 Pub&Sub通信のチュートリアルを実施し、ワークスペース
ros2_lecture_ws
を作成する。 - 実習ROS 2 Qtを使う1 Qtの環境構築を実施する。
ROS 2パッケージの作成
パッケージqt_pubsub
を作成する。
cd ~/ros2_lecture_ws/src
ros2 pkg create --build-type ament_cmake qt_pubsub
ソースコードの作成
publisherとsubscriberの2つのROSノードを作成する。publisherのGUIにはテキストボックスとプッシュボタンを配置し、テキストボックスに入力した文字列をpublishする。subscriberのGUIにはテキストボックスを配置し、subscribeしたトピックの文字列を表示する。
publisherの作成
ディレクトリqt_pubsub/src/
内に、以下の5つのソースファイルを作成する。
-
ROSノード
クラスQtTalker
ではROSノードqt_talker
を定義し、文字列型のトピックchatter
のpublisherを作成する。また、メンバ関数publish_message()
は、引数で指定された文字列をトピックに格納し、トピックchatter
をpublishする関数である。 -
Qt
クラスMainDialog
で1行のテキストエディタ、プッシュボタンを配置したダイアログを定義している。ボタンをクリックするとpublishString()
が実行されるように、ボタンクリックのシグナルと自作スロットpublishString()
を接続した。
publishString()
ではテキストエディタから文字列を取得し、ROSノードのpublish_message()
へと文字列を渡している。 -
実行
ROSとQtを組み合わせるにあたり、QtやROSの処理を実行する方法を工夫する必要がある。一般的に使用されるROSのspin()
やQtのexec()
は、ROSやQtの処理が終了するまでループ処理を行う。したがって、これらを利用するとQtかROSのどちらか一方しか実行できない。
そこで、ROSはspin_some()
、QtはprocessEvents()
で処理を実行するとともに、whileを使ってループ構造を実装している。spin_some()は、関数が呼び出された時点で実行できるROSの処理を行う。processEvents()も同様に、関数呼び出し時点で実行できるQtの処理を行う関数である。// 実行 while (rclcpp::ok()) { rclcpp::spin_some(rosNode); app.processEvents(); }
subscriberの作成
ディレクトリqt_pubsub/src/
内に、以下の5つのソースファイルを作成する。
- qt_listener.cpp
- qt_listener_GUI.hpp
- qt_listener_GUI.cpp
- qt_listener_rosNode.hpp
- qt_listener_rosNode.cpp
- ROSノード
クラスQtListener
ではROSノードqt_listener
を定義し、文字列型のトピックchatter
のsubscriberを作成する。トピック購読時のコールバック関数にchatter_callback()
を指定している。
chatter_callback
は引数で受け取ったメッセージから文字列を取り出し、QtのstringCallback()
関数に渡す。 - Qt
クラスMainDialog
で1行のテキストエディタを配置したダイアログを定義している。メンバ関数stringCallback()
は、引数で指定された文字列をテキストエディタに出力する関数である。 - 実行
qt_talker
での実装と同様に、spin_some()
およびprocessEvents()
利用してROSとQtの処理を行う。
ビルドの設定
CMakeLists.txtおよびpackage.xmlにビルド設定を記述する。追加する行を以下に示す。
-
CMakeLists.txt
他のパッケージへの依存を解決し、マクロQ_OBJECT
を利用するための設定、実行ファイルの作成に関して追記する。また、ビルド結果をinstall/
配下に作成して、ROS 2コマンドで実行できるように設定している。find_package(ament_cmake REQUIRED) + find_package(rclcpp REQUIRED) + find_package(std_msgs REQUIRED) + # packages for Qt + find_package(Qt5Core REQUIRED) + find_package(Qt5Widgets REQUIRED) + set(CMAKE_AUTOMOC ON) + add_executable(qt_talker src/qt_talker.cpp src/qt_talker_GUI.cpp src/qt_talker_rosNode.cpp) + add_executable(qt_listener src/qt_listener.cpp src/qt_listener_GUI.cpp src/qt_listener_rosNode.cpp) + ament_target_dependencies(qt_talker rclcpp Qt5Core Qt5Widgets) + ament_target_dependencies(qt_listener rclcpp Qt5Core Qt5Widgets) + install( + TARGETS + qt_talker + qt_listener + DESTINATION lib/${PROJECT_NAME} + ) if(BUILD_TESTING) find_package(ament_lint_auto REQUIRED)
-
package.xml
他パッケージへの依存を記述する。+ <depend>rclcpp</depend> + <depend>std_msgs</depend> + <build_depend>qtbase5-dev</build_depend>
ROSノードの起動
作成したパッケージをビルドし、ノードqt_talker
とqt_listener
を実行する。
-
パッケージのビルド
cd ~/ros2_lecture_ws/ colcon build
-
qt_talkerの起動
1つ目の端末で以下を実行する。. install/setup.bash ros2 run qt_pubsub qt_talker
-
qt_listenerの起動
2つ目の端末で以下を実行する。. install/setup.bash ros2 run qt_pubsub qt_listener
qt_talker
を起動すると以下のようなウィンドウが表示される。1段目のエディタに文字を入力してボタンをクリックするとトピックが送信される。
qt_listener
を起動すると以下のようなウィンドウが表示される。トピックを購読すると、受信したメッセージが表示される。