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_AUTOMOCやqt5_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.xmlのclass typeには、PLUGINLIB_EXPORT_CLASS
で指定したクラス名と同じ名前を指定します。名前空間を付けた場合は、XML
側にも同じ名前空間付きのクラス名を記述します。
CMakeLists.txtの修正
CMakeLists.txtのament_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 
- 本ページには、弊社独自の考察・見解を記述している箇所がございます。
- 本ページの利用によって生じたいかなるトラブル・損害等について当社は一切責任を負わないものとします。
- 本ページは予告なく内容の変更や削除を行う場合があります。