本文へスキップします。

本文へ

サービスサイトロゴ

株式会社SRA

サービスサイトヘッダーリンク

承認:エディタ

RVizのプラグイン作成

(掲載 2026年07月17日)

本記事のゴール

本記事では/cmd_velトピックをpublishできるパネルをRVizプラグインとして作成し、Rviz上に追加・動作させることをゴールとしています。
/cmd_velはロボットの移動速度を指令するためのトピックです。

RVizプラグインについて

RVizプラグインは、RVizのUIにカスタムGUIを追加できる仕組みであり、ロボットの操作パネルやデバッグツールの実装に利用されます。

RVizはQtと呼ばれるGUIツールキットで開発されていることから、RVizプラグインもQtを利用して開発することになります。
また、記事執筆時点(2026年6月)でのQtの最新のLTSはQt6系(Qt 6.8)になりますが、本記事の前提とするROS2 JazzyではQt5系(Qt 5.15 LTS)が利用されており、紹介するサンプルコードもQt5系に準じたものになります。
Qtプログラミングについて理解を深めたい方は以下のページ等を参考にしてください。
https://doc.qt.io/archives/qt-5.15/metaobjects.html

前提条件

本記事は以下を前提としています。

パッケージの雛形の作成

ROS2のワークスペース(~/ros2_ws)のsrcディレクトリ以下で以下のコマンドを実行し、パッケージを作成します。

$ cd ~/ros2_ws/src
$ ros2 pkg create --build-type ament_cmake rviz_panel_sample

ヘッダ、ソースコードの作成

作成したパッケージ配下に、include/rviz_panel_sample/panel_sample.hppを以下の内容で作成します。

#pragma once

#include <rviz_common/panel.hpp>
#include <rclcpp/rclcpp.hpp>
#include <geometry_msgs/msg/twist.hpp>

#include <QPushButton>
#include <QSlider>
#include <QVBoxLayout>

class PanelSample : public rviz_common::Panel
{
Q_OBJECT
public:
  PanelSample(QWidget * parent = nullptr);

protected:
  void forward();
  void stop();
  void backward();

private:
  rclcpp::Node::SharedPtr node_;
  rclcpp::Publisher<geometry_msgs::msg::Twist>::SharedPtr pub_;

  QPushButton * forward_button_;
  QPushButton * stop_button_;
  QPushButton * backward_button_;
  QSlider * slider_;
};

Q_OBJECTはQtのシグナル・スロットを利用するために必要です。ヘッダに Q_OBJECTを書いた場合、CMake側でMOCによるコード生成が必要になるため、CMAKE_AUTOMOCqt5_wrap_cppを設定します。

また、src/panel_sample.cppを以下の内容で作成します。

#include "rviz_panel_sample/panel_sample.hpp"

#include <QTimer>

PanelSample::PanelSample(QWidget * parent)
: Panel(parent)
{
  node_ = std::make_shared<rclcpp::Node>("rviz_command_panel");
  pub_ = node_->create_publisher<geometry_msgs::msg::Twist>("/cmd_vel", 10);

  forward_button_ = new QPushButton("Forward");
  stop_button_ = new QPushButton("Stop");
  backward_button_ = new QPushButton("Backward");

  slider_ = new QSlider(Qt::Horizontal);
  slider_->setRange(0, 100);
  slider_->setValue(50);

  QVBoxLayout * layout = new QVBoxLayout;
  layout->addWidget(forward_button_);
  layout->addWidget(stop_button_);
  layout->addWidget(backward_button_);
  layout->addWidget(slider_);
  setLayout(layout);

  connect(forward_button_, &QPushButton::clicked, this, &PanelSample::forward);
  connect(stop_button_, &QPushButton::clicked, this, &PanelSample::stop);
  connect(backward_button_, &QPushButton::clicked, this, &PanelSample::backward);

  auto timer = new QTimer(this);
  connect(timer, &QTimer::timeout, [this]() {
    rclcpp::spin_some(node_);
  });
  timer->start(100);
}

void PanelSample::forward()
{
  geometry_msgs::msg::Twist msg;
  msg.linear.x = slider_->value() / 100.0;
  pub_->publish(msg);
}

void PanelSample::backward()
{
  geometry_msgs::msg::Twist msg;
  msg.linear.x = -slider_->value() / 100.0;
  pub_->publish(msg);
}

void PanelSample::stop()
{
  geometry_msgs::msg::Twist msg;
  pub_->publish(msg);
}

#include <pluginlib/class_list_macros.hpp>
PLUGINLIB_EXPORT_CLASS(PanelSample, rviz_common::Panel)

なお、今回のサンプルコードでは簡略化のためグローバルな名前空間にクラス定義していますが、実際の開発では名前空間付きで定義することが推奨されます。

また、今回のサンプルはpublishのみなので必須ではありませんが、subscriberやserviceを扱う場合にコールバックを処理できるよう、QTimerで定期的にspin_some()を呼び出しています。

package.xmlの修正

依存パッケージに以下を追記します。

<depend>pluginlib</depend>
<depend>rviz_common</depend>

rviz_common_plugins.xmlの作成

rviz_common_plugins.xmlを以下の内容で作成します。

<library path="rviz_panel_sample">
  <class type="PanelSample" base_class_type="rviz_common::Panel">
    <description></description>
  </class>
</library>

rviz_common_plugins.xmlclass typeには、PLUGINLIB_EXPORT_CLASS で指定したクラス名と同じ名前を指定します。名前空間を付けた場合は、XML 側にも同じ名前空間付きのクラス名を記述します。

CMakeLists.txtの修正

CMakeLists.txtament_package()の前に、以下の内容を追記します。

find_package(ament_cmake_ros REQUIRED)
find_package(pluginlib REQUIRED)
find_package(rviz_common REQUIRED)

set(CMAKE_AUTOMOC ON)
qt5_wrap_cpp(MOC_FILES
  include/rviz_panel_sample/panel_sample.hpp
)

add_library(rviz_panel_sample src/panel_sample.cpp ${MOC_FILES})
target_include_directories(rviz_panel_sample PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>
)
ament_target_dependencies(rviz_panel_sample
  pluginlib
  rviz_common
)
install(TARGETS rviz_panel_sample
  EXPORT export_rviz_panel_sample
  ARCHIVE DESTINATION lib
  LIBRARY DESTINATION lib
  RUNTIME DESTINATION bin
)
install(DIRECTORY include/
  DESTINATION include
)
install(FILES rviz_common_plugins.xml
  DESTINATION share/${PROJECT_NAME}
)
ament_export_include_directories(include)
ament_export_targets(export_rviz_panel_sample)
pluginlib_export_plugin_description_file(rviz_common rviz_common_plugins.xml)

ビルド

ワークスペース(~/ros2_ws等)でプラグインをビルドします。

$ cd ~/ros2_ws
$ colcon build --packages-select rviz_panel_sample

NOTE
開発に必要なQt関連のライブラリはros-jazzy-desktopの依存関係の都合上インストール済みとなっているはずですが、Qtが見つからない等のビルドエラーが発生する場合は以下のコマンドを実行してQtをインストール後、再度ビルドしてください

$ sudo apt install qtbase5-dev qt5-qmake qttools5-dev-tools qttools5-dev

動作確認

setup.bashを実行し、RVizを起動します。

$ source install/setup.bash
$ rviz2

メニューバーのPanels → Add New Panelを選択すると、作成したパネルがリストアップされるため、それを選択してOKボタンを押します。

OKボタンを押すと、以下のように作成したパネルがRViz上に追加されます。

パネル上に配置したボタンが機能していることを確認するため、ターミナルを起動して、以下のコマンドで/cmd_velトピックを監視しておきます。

$ ros2 topic echo /cmd_vel geometry_msgs/msg/Twist

追加したパネルでForwardボタンやBackwardボタンを押すと、ros2 topicコマンドを実行しているターミナルで以下のように表示され、/cmd_velトピックが発行されていることを確認できます。

linear:
  x: 0.5
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 0.0
---

RViz上でロボットモデルを表示可能な環境の場合(TurtleBot3のturtlebot3_fake_node等)、RViz上での移動を確認することも可能です。

turtlebot3_fake_nodeの場合、最後の/cmd_vel受信から1秒間経過すると速度を0にもどすタイムアウトが設けられていますので、パネルのForward/Backwardボタンを押すと1秒間前進/後退して停止する動作になります。

まとめ

この記事では、RViz上に独自UIを実装し、ロボットの操作ができることを確認してきました。

SRAでは、ROSの環境構築から各種開発まで幅広く支援いたします。(お問い合わせはこちら

参考: Building a Custom RViz Panel


  • 本ページには、弊社独自の考察・見解を記述している箇所がございます。
  • 本ページの利用によって生じたいかなるトラブル・損害等について当社は一切責任を負わないものとします。
  • 本ページは予告なく内容の変更や削除を行う場合があります。