Skip to content

Commit e2aee50

Browse files
authored
feat(tier4_metrics_rviz_plugin): add selected metrics view tab (#6577)
1 parent 9993a9e commit e2aee50

File tree

3 files changed

+164
-13
lines changed

3 files changed

+164
-13
lines changed

evaluator/tier4_metrics_rviz_plugin/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ find_package(Qt5 REQUIRED Core Widgets Charts)
88
set(QT_WIDGETS_LIB Qt5::Widgets)
99
set(QT_CHARTS_LIB Qt5::Charts)
1010
set(CMAKE_AUTOMOC ON)
11-
set(CMAKE_INCLUDE_CURRENT_DIR ON)
1211
add_definitions(-DQT_NO_KEYWORDS)
1312

1413
ament_auto_add_library(${PROJECT_NAME} SHARED
1514
src/metrics_visualize_panel.cpp
15+
include/metrics_visualize_panel.hpp
1616
)
1717

1818
target_link_libraries(${PROJECT_NAME}

evaluator/tier4_metrics_rviz_plugin/src/metrics_visualize_panel.hpp evaluator/tier4_metrics_rviz_plugin/include/metrics_visualize_panel.hpp

+35-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <QLabel>
2626
#include <QLineSeries>
2727
#include <QPainter>
28+
#include <QPushButton>
2829
#include <QTableWidget>
2930
#include <QVBoxLayout>
3031
#endif
@@ -34,11 +35,13 @@
3435

3536
#include <diagnostic_msgs/msg/diagnostic_array.hpp>
3637

38+
#include <iostream>
3739
#include <limits>
3840
#include <string>
3941
#include <unordered_map>
4042
#include <utility>
4143
#include <vector>
44+
4245
namespace rviz_plugins
4346
{
4447

@@ -148,6 +151,8 @@ struct Metric
148151

149152
QTableWidget * getTable() const { return table; }
150153

154+
std::unordered_map<std::string, QLabel *> getLabels() const { return labels; }
155+
151156
private:
152157
static std::optional<std::string> getValue(const DiagnosticStatus & status, std::string && key)
153158
{
@@ -188,29 +193,58 @@ class MetricsVisualizePanel : public rviz_common::Panel
188193
void onInitialize() override;
189194

190195
private Q_SLOTS:
196+
// Slot functions triggered by UI events
191197
void onTopicChanged();
198+
void onSpecificMetricChanged();
199+
void onClearButtonClicked();
200+
void onTabChanged();
192201

193202
private:
203+
// ROS 2 node and subscriptions for handling metrics data
194204
rclcpp::Node::SharedPtr raw_node_;
195205
rclcpp::TimerBase::SharedPtr timer_;
196206
std::unordered_map<std::string, rclcpp::Subscription<DiagnosticArray>::SharedPtr> subscriptions_;
207+
208+
// Topics from which metrics are collected
197209
std::vector<std::string> topics_ = {
198210
"/diagnostic/planning_evaluator/metrics", "/diagnostic/perception_online_evaluator/metrics"};
199211

212+
// Timer and metrics message callback
200213
void onTimer();
201214
void onMetrics(const DiagnosticArray::ConstSharedPtr & msg, const std::string & topic_name);
202215

216+
// Functions to update UI based on selected metrics
217+
void updateViews();
218+
void updateSelectedMetric(const std::string & metric_name);
219+
220+
// UI components
203221
QGridLayout * grid_;
204222
QComboBox * topic_selector_;
223+
QTabWidget * tab_widget_;
205224

206-
// <topic_name, <metric_name, <table, chart>>>
225+
// "Specific Metrics" tab components
226+
QComboBox * specific_metric_selector_;
227+
QChartView * specific_metric_chart_view_;
228+
QTableWidget * specific_metric_table_;
229+
230+
// Selected metrics data
231+
std::optional<std::pair<std::string, Metric>> selected_metrics_;
232+
233+
// Cache for received messages by topics
234+
std::unordered_map<std::string, DiagnosticArray::ConstSharedPtr> current_msg_map_;
235+
236+
// Mapping from topics to metrics widgets (tables and charts)
207237
std::unordered_map<
208238
std::string, std::unordered_map<std::string, std::pair<QTableWidget *, QChartView *>>>
209239
topic_widgets_map_;
210240

241+
// Synchronization
211242
std::mutex mutex_;
243+
244+
// Stored metrics data
212245
std::unordered_map<std::string, Metric> metrics_;
213246

247+
// Utility functions for managing widget visibility based on topics
214248
void updateWidgetVisibility(const std::string & target_topic, const bool show);
215249
void showCurrentTopicWidgets();
216250
void hideInactiveTopicWidgets();

evaluator/tier4_metrics_rviz_plugin/src/metrics_visualize_panel.cpp

+128-11
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,53 @@ namespace rviz_plugins
2929
MetricsVisualizePanel::MetricsVisualizePanel(QWidget * parent)
3030
: rviz_common::Panel(parent), grid_(new QGridLayout())
3131
{
32-
setLayout(grid_);
32+
// Initialize the main tab widget
33+
tab_widget_ = new QTabWidget();
34+
35+
// Create and configure the "All Metrics" tab
36+
QWidget * all_metrics_widget = new QWidget();
37+
grid_ = new QGridLayout(all_metrics_widget); // Apply grid layout to the widget directly
38+
all_metrics_widget->setLayout(grid_);
39+
40+
// Add topic selector combobox
3341
topic_selector_ = new QComboBox();
3442
for (const auto & topic : topics_) {
3543
topic_selector_->addItem(QString::fromStdString(topic));
3644
}
37-
grid_->addWidget(topic_selector_, 0, 0, 1, -1);
45+
grid_->addWidget(topic_selector_, 0, 0, 1, -1); // Add topic selector to the grid layout
3846
connect(topic_selector_, SIGNAL(currentIndexChanged(int)), this, SLOT(onTopicChanged()));
47+
48+
tab_widget_->addTab(
49+
all_metrics_widget, "All Metrics"); // Add "All Metrics" tab to the tab widget
50+
51+
// Create and configure the "Specific Metrics" tab
52+
QWidget * specific_metrics_widget = new QWidget();
53+
QVBoxLayout * specific_metrics_layout = new QVBoxLayout();
54+
specific_metrics_widget->setLayout(specific_metrics_layout);
55+
56+
// Add specific metric selector combobox
57+
specific_metric_selector_ = new QComboBox();
58+
specific_metrics_layout->addWidget(specific_metric_selector_);
59+
connect(
60+
specific_metric_selector_, SIGNAL(currentIndexChanged(int)), this,
61+
SLOT(onSpecificMetricChanged()));
62+
63+
// Add clear button
64+
QPushButton * clear_button = new QPushButton("Clear");
65+
specific_metrics_layout->addWidget(clear_button);
66+
connect(clear_button, &QPushButton::clicked, this, &MetricsVisualizePanel::onClearButtonClicked);
67+
68+
// Add chart view for specific metrics
69+
specific_metric_chart_view_ = new QChartView();
70+
specific_metrics_layout->addWidget(specific_metric_chart_view_);
71+
72+
tab_widget_->addTab(
73+
specific_metrics_widget, "Specific Metrics"); // Add "Specific Metrics" tab to the tab widget
74+
75+
// Set the main layout of the panel
76+
QVBoxLayout * main_layout = new QVBoxLayout();
77+
main_layout->addWidget(tab_widget_);
78+
setLayout(main_layout);
3979
}
4080

4181
void MetricsVisualizePanel::onInitialize()
@@ -91,6 +131,56 @@ void MetricsVisualizePanel::onTopicChanged()
91131
showCurrentTopicWidgets();
92132
}
93133

134+
void MetricsVisualizePanel::updateSelectedMetric(const std::string & metric_name)
135+
{
136+
std::lock_guard<std::mutex> message_lock(mutex_);
137+
138+
for (const auto & [topic, msg] : current_msg_map_) {
139+
const auto time = msg->header.stamp.sec + msg->header.stamp.nanosec * 1e-9;
140+
for (const auto & status : msg->status) {
141+
if (metric_name == status.name) {
142+
selected_metrics_ = {metric_name, Metric(status)};
143+
selected_metrics_->second.updateData(time, status);
144+
return;
145+
}
146+
}
147+
}
148+
}
149+
150+
void MetricsVisualizePanel::updateViews()
151+
{
152+
if (!selected_metrics_) {
153+
return;
154+
}
155+
156+
Metric & metric = selected_metrics_->second;
157+
specific_metric_chart_view_->setChart(metric.getChartView()->chart());
158+
auto * specific_metrics_widget = dynamic_cast<QWidget *>(tab_widget_->widget(1));
159+
auto * specific_metrics_layout = dynamic_cast<QVBoxLayout *>(specific_metrics_widget->layout());
160+
specific_metrics_layout->removeWidget(specific_metric_table_);
161+
specific_metric_table_ = metric.getTable();
162+
QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
163+
sizePolicy.setHeightForWidth(specific_metric_table_->sizePolicy().hasHeightForWidth());
164+
specific_metric_table_->setSizePolicy(sizePolicy);
165+
specific_metrics_layout->insertWidget(1, specific_metric_table_);
166+
}
167+
168+
void MetricsVisualizePanel::onSpecificMetricChanged()
169+
{
170+
const auto selected_metrics_str = specific_metric_selector_->currentText().toStdString();
171+
updateSelectedMetric(selected_metrics_str);
172+
updateViews();
173+
}
174+
175+
void MetricsVisualizePanel::onClearButtonClicked()
176+
{
177+
if (!selected_metrics_) {
178+
return;
179+
}
180+
updateSelectedMetric(selected_metrics_->first);
181+
updateViews();
182+
}
183+
94184
void MetricsVisualizePanel::onTimer()
95185
{
96186
std::lock_guard<std::mutex> message_lock(mutex_);
@@ -99,6 +189,11 @@ void MetricsVisualizePanel::onTimer()
99189
metric.updateGraph();
100190
metric.updateTable();
101191
}
192+
193+
if (selected_metrics_) {
194+
selected_metrics_->second.updateGraph();
195+
selected_metrics_->second.updateTable();
196+
}
102197
}
103198

104199
void MetricsVisualizePanel::onMetrics(
@@ -117,26 +212,48 @@ void MetricsVisualizePanel::onMetrics(
117212

118213
// Calculate grid position
119214
const size_t row = num_current_metrics / GRAPH_COL_SIZE * 2 +
120-
1; // start from 1 to leave space for the topic selector
215+
2; // start from 2 to leave space for the topic selector and tab widget
121216
const size_t col = num_current_metrics % GRAPH_COL_SIZE;
122217

123218
// Get the widgets from the metric
124219
const auto tableWidget = metric.getTable();
125220
const auto chartViewWidget = metric.getChartView();
126221

127-
// Add the widgets to the grid layout
128-
grid_->addWidget(tableWidget, row, col);
129-
grid_->setRowStretch(row, false);
130-
grid_->addWidget(chartViewWidget, row + 1, col);
131-
grid_->setRowStretch(row + 1, true);
132-
grid_->setColumnStretch(col, true);
222+
// Get the layout for the "All Metrics" tab
223+
auto all_metrics_widget = dynamic_cast<QWidget *>(tab_widget_->widget(0));
224+
QGridLayout * all_metrics_layout = dynamic_cast<QGridLayout *>(all_metrics_widget->layout());
133225

134-
// Also add the widgets to the graph_widgets_ vector for easy removal later
226+
// Add the widgets to the "All Metrics" tab layout
227+
all_metrics_layout->addWidget(tableWidget, row, col);
228+
all_metrics_layout->setRowStretch(row, false);
229+
all_metrics_layout->addWidget(chartViewWidget, row + 1, col);
230+
all_metrics_layout->setRowStretch(row + 1, true);
231+
all_metrics_layout->setColumnStretch(col, true);
232+
233+
// Also add the widgets to the topic_widgets_map_ for easy management
135234
topic_widgets_map_[topic_name][status.name] = std::make_pair(tableWidget, chartViewWidget);
136235
}
137-
138236
metrics_.at(status.name).updateData(time, status);
237+
238+
// update selected metrics
239+
const auto selected_metrics_str = specific_metric_selector_->currentText().toStdString();
240+
if (selected_metrics_str == status.name) {
241+
if (selected_metrics_) {
242+
selected_metrics_->second.updateData(time, status);
243+
}
244+
}
139245
}
246+
247+
// Update the specific metric selector
248+
QSignalBlocker blocker(specific_metric_selector_);
249+
for (const auto & status : msg->status) {
250+
if (specific_metric_selector_->findText(QString::fromStdString(status.name)) == -1) {
251+
specific_metric_selector_->addItem(QString::fromStdString(status.name));
252+
}
253+
}
254+
255+
// save the message for metrics selector
256+
current_msg_map_[topic_name] = msg;
140257
}
141258

142259
} // namespace rviz_plugins

0 commit comments

Comments
 (0)