ROS2 + Qt Quickを使ったシステム開発

効率的にロボットシステムを構築するための仕組みであるROS。
ISPでは、ROSとGUIフレームワークであるQtを組み合わせたシステム開発も行っています。

今回はROSの新しい仕組みである「ROS2」と「Qt」を組み合わせたシステム開発ができるかどうか挑戦してみました。

前置き 〜ROSとQt〜

ROSはロボット用途なのだから、GUIなんて要らないんじゃ…と思われるかもしれませんが、そんなことはありません。
ロボットが動作するための各種センサデータの可視化やロボットモジュールの細かい操作を始めとして、GUIがあると便利な場面は多々あります。

そして、ROS上のQtの扱いですが、ROSトピックの可視化等に使われるツール「rqt」がQtをベースとしているようにROS通信とQtは連携可能です。
rqtを使わず、Qt単体でもROS通信を利用したGUIツールを開発することができます。
※ 今回は rqt をカスタマイズせず、Qtでのアプリケーション作成を目的としています。

今回作成したサンプル

今回は簡単に、以下のpublisher、subscriberで動作するシステムを構築しました。

  • (Publisher) OpenCV で取得したカメラ画像を送信する。
  • (Subscriber) (Qt内) 受信した画像を逐次表示更新。
concept

作成したサンプルは github 上に置いています。

  ROS2_Qt_image_transport

環境

  • Ubuntu 18.04
    • ROS2 crystal
    • Qt 5.9
    • OpenCV 3.4.0
  • PCにUSBカメラが接続されていること

作成のポイント

Publisher 側

Publisher 側はシンプルに、OpenCVから取得したカメラ映像を /camera/image トピックで送信しているだけです。
送信についてはROS2のサンプルを参照しました。

  ros2/demos (cam2image.cpp)

ROS2ビルド可能 & QtCreatorビルド可能なQt Quickアプリケーション

Qtでのスムーズなアプリケーション構築のために、ROS2ビルドだけでなく、QtCreator上でもビルドできるようにしておきたいところです。

調べたところ、以下3つのポイントを押さえて実装することで、上記を満たすアプリケーションが作成できました。

  1. Qt Quick アプリケーションを選択。ビルドシステムは「qmake」を選択する。
  2. 生成されたソースコード群は ros2 pkg create したディレクトリ配下の src に投下。
  3. ROS2用のCMakeLists.txtでは src 配下を見に行くように設定。

このように実装すると、

  • ROS2ビルド … CMakeLists.txt の設定でビルド可能。
  • Qtビルド … src配下でソースコード完結しているので、そのままqmakeでビルド可能。

となります。
[参照]
  Medium (Amar Lakshya) : Qt5 and ROS2 — Finally together!

ROS spin() や Qt app.exec() の扱い

ROSでsubscriberを実装する際、受信待ちのため「spin()」処理を呼ぶ必要があります。しかし、処理がブロックされてしまうため、これを呼ぶとウィンドウが動かなくなってしまいます。
逆に、Qtアプリケーションの方も「app.exec()」を呼ばないとウィンドウの処理が動きませんが、これもブロッキングな処理なので、同様にROSの方が動かなくなってしまいます。

どちらもノンブロッキングな処理に差し替えることで問題を解消することができました。

  • ROS2側 … while ループで「rclcpp::spin_some(node)」を呼び出す。
  • Qt側 … ノンブロッキングな処理「app.processEvent()」に変更。ROS2側の while ループ内で一緒に呼ぶ。

Qt Quick 上の動画の表示

Qt Quickは今回初めて使用しましたが、慣れれば使いやすいですね。動画表示は参照記事を元にして実装しました。
動画IDを更新すると表示が更新されるので、subscriberが受信した画像を画像表示クラスのメンバ変数に渡して常に更新表示させています。

[参照]
  凹みTips : QML から OpenCV で取得したカメラ画を表示してみた

ROS2でもQtでもビルド可能にする

ROS2だけでなくQtでもビルドができるようにしたので、ソースコードもそのように実装したいところ。

今回は、Qt上のROS2コードを「#ifdef ROS 〜 #endif」で囲んで qmake 時には通らないようにしました。
ROS2ビルドでは逆にコンパイル時に通るよう、CMakelists.txt内で

add_definitions(-DROS)

を定義することにより要求を満たすようにしています。

なお、Qt上で実行すると画像が送られてこないため、緑一色のウィンドウが表示され、
ROS2上で実行し、画像が送られてくると、その画像が表示されます。

結果と課題

ここまでで、ROS2とQtを使った (簡単な) システムを構築することができました。
launch ファイルを用意してあるので、colconビルド後、ros2 launchコマンドで実行可能です。

$ source /opt/ros/crystal/setup.bash
$ colcon build –symlink-install
$ source install/setup.bash
$ ros2 launch image_sender exec.py

実行すると、USBカメラの画像がウィンドウに表示されます。

比較として、通常のROS2 + OpenCVウィンドウも表示し、映り方を比べてみました。

左がOpenCV、右がQtですが、どちらも速度のズレなく表示されているのがわかります。
左がOpenCV、右がQtですが、どちらも速度のズレなく表示されているのがわかります。

まとめ

ROS2 + Qt を用いたシステム構築を試してみました。
ROS2 はその仕組み上、ROS よりも効率的に動作し、今後のロボティクス分野に多く使われるツールとなると考えています。
今までのROSの知見を活かしつつ、ROS2も積極的に使っていきたいです。