dataload_ros2.cpp
Go to the documentation of this file.
1 #include "dataload_ros2.h"
2 #include <QTextStream>
3 #include <QFile>
4 #include <QMessageBox>
5 #include <QPushButton>
6 #include <QDebug>
7 #include <QApplication>
8 #include <QProgressDialog>
9 #include <QFileInfo>
10 #include <QDir>
11 #include <QProcess>
12 #include <QSettings>
13 #include <QElapsedTimer>
14 #include <set>
15 #include <QDebug>
16 #include <rosidl_typesupport_introspection_cpp/identifier.hpp>
17 #include <rosidl_typesupport_introspection_cpp/message_introspection.hpp>
18 #include <rosidl_typesupport_introspection_cpp/field_types.hpp>
19 #include <rosidl_typesupport_cpp/identifier.hpp>
20 #include <rosbag2_cpp/typesupport_helpers.hpp>
21 #include <rosbag2_cpp/storage_options.hpp>
22 #include <rosbag2_cpp/types/introspection_message.hpp>
23 #include <unordered_map>
24 #include <rclcpp/rclcpp.hpp>
25 #include <rmw/rmw.h>
26 
27 #include "../dialog_select_ros_topics.h"
28 
30 {
31  _extensions.push_back("yaml");
33 }
34 
35 const std::vector<const char*>& DataLoadROS2::compatibleFileExtensions() const
36 {
37  return _extensions;
38 }
39 
41  PJ::PlotDataMapRef& plot_map)
42 {
43  auto metadata_io = std::make_unique<rosbag2_storage::MetadataIo>();
44 
45  auto temp_bag_reader = std::make_shared<rosbag2_cpp::readers::SequentialReader>();
46 
47  QString bagDir;
48  {
49  QFileInfo finfo(info->filename);
50  bagDir = finfo.dir().path();
51  }
52 
53  rosbag2_cpp::StorageOptions storageOptions;
54  storageOptions.uri = bagDir.toStdString();
55  storageOptions.storage_id = "sqlite3";
56  rosbag2_cpp::ConverterOptions converterOptions;
57  converterOptions.input_serialization_format = "cdr";
58  converterOptions.output_serialization_format = rmw_get_serialization_format();
59 
60  QString oldPath = QDir::currentPath();
61  QDir::setCurrent(QDir::cleanPath(bagDir + QDir::separator() + ".."));
62 
63  try
64  {
65  temp_bag_reader->open(storageOptions, converterOptions);
66  }
67  catch (std::runtime_error& ex)
68  {
69  QMessageBox::warning(nullptr, tr("Error"), QString("rosbag::open thrown an exception:\n") + QString(ex.what()));
70  return false;
71  }
72  const auto bag_metadata = metadata_io->read_metadata(storageOptions.uri);
73 
74  QDir::setCurrent(oldPath);
75 
76  // Temporarily change the current directory as a workaround for rosbag2 relative directories not working properly
77  std::vector<rosbag2_storage::TopicMetadata> topic_metadata = temp_bag_reader->get_all_topics_and_types();
78 
79  std::unordered_map<std::string, std::string> topicTypesByName;
80 
81  std::vector<std::pair<QString, QString>> all_topics_qt;
82 
83  std::vector<TopicInfo> topics_info;
84 
85  std::set<std::string> blacklist_topic_name;
86  std::set<std::string> failed_topic_type;
87 
88  for (const rosbag2_storage::TopicMetadata& topic : topic_metadata)
89  {
90  all_topics_qt.push_back( {QString::fromStdString(topic.name),
91  QString::fromStdString(topic.type)} );
92  topicTypesByName.emplace(topic.name, topic.type);
93 
94  TopicInfo topic_info;
95  topic_info.name = topic.name;
96  topic_info.type = topic.type;
97 
98  const auto& typesupport_identifier = rosidl_typesupport_cpp::typesupport_identifier;
99  try
100  {
101  const auto& typesupport_library = rosbag2_cpp::get_typesupport_library(topic.type,
102  typesupport_identifier);
103  topic_info.type_support = rosbag2_cpp::get_typesupport_handle(topic.type,
104  typesupport_identifier,
105  typesupport_library);
106  topics_info.emplace_back( std::move(topic_info) );
107 
108  } catch (...) {
109  failed_topic_type.insert(topic.type);
110  blacklist_topic_name.insert(topic.type);
111  }
112  }
113 
114  if(!failed_topic_type.empty())
115  {
116  QString msg("Can not recognize the following message types and those topics will be ignored:\n\n");
117  for(const auto& type: failed_topic_type)
118  {
119  msg += " " + QString::fromStdString(type) + "\n";
120  }
121  msg += "\nHave you forgotten to source your workspace?";
122  QMessageBox::warning(nullptr, tr("Error"), msg);
123  }
124 
125  if (info->plugin_config.hasChildNodes())
126  {
127  xmlLoadState(info->plugin_config.firstChildElement());
128  }
129 
130  if (!info->selected_datasources.empty())
131  {
133  }
134  else
135  {
136  DialogSelectRosTopics* dialog = new DialogSelectRosTopics(all_topics_qt, _config);
137 
138  if (dialog->exec() != static_cast<int>(QDialog::Accepted))
139  {
140  delete dialog;
141  return false;
142  }
143  _config = dialog->getResult();
144  delete dialog;
145  }
146 
147  //--- Swith the previous bag with this one
148  // clean up previous MessageInstances
149  plot_map.user_defined.clear();
150 
151  if (_bag_reader)
152  {
153  _bag_reader->reset();
154  }
155  _bag_reader = temp_bag_reader;
156  //---------------------------------------
157 
159 
160  Ros2CompositeParser parser(plot_map);
161 
162  std::set<std::string> topic_selected;
163  for (const auto& topic_qt : _config.topics)
164  {
165  std::string topic_name = topic_qt.toStdString();
166  std::string topic_type = topicTypesByName.at(topic_name);
167  topic_selected.insert(topic_name);
168 
169  parser.registerMessageType(topic_name, topic_type);
170  }
171 
172  parser.setConfig(_config);
173 
174  QProgressDialog progress_dialog;
175  progress_dialog.setLabelText("Loading... please wait");
176  progress_dialog.setWindowModality(Qt::ApplicationModal);
177  progress_dialog.setRange(0, bag_metadata.message_count);
178  progress_dialog.show();
179  int msg_count = 0;
180 
181  PJ::PlotDataAny& plot_consecutive =
182  plot_map.addUserDefined("plotjuggler::rosbag2_cpp::consecutive_messages")->second;
183  PJ::PlotDataAny& metadata_storage =
184  plot_map.addUserDefined("plotjuggler::rosbag2_cpp::topics_metadata")->second;
185 
186  // dirty trick. Store it in a one point timeseries
187  metadata_storage.pushBack( {0, std::any(topics_info) } );
188 
189  auto time_prev = std::chrono::high_resolution_clock::now();
190 
191  while (_bag_reader->has_next())
192  {
193  auto msg = _bag_reader->read_next();
194  const std::string& topic_name = msg->topic_name;
195  if(blacklist_topic_name.count(topic_name))
196  {
197  continue;
198  }
199  const double msg_timestamp = 1e-9 * double(msg->time_stamp); // nanoseconds to seconds
200 
201  //------ progress dialog --------------
202  if (msg_count++ % 100 == 0)
203  {
204  progress_dialog.setValue(msg_count);
205  QApplication::processEvents();
206 
207  if (progress_dialog.wasCanceled())
208  {
209  return false;
210  }
211  }
212 
213  //----- skip not selected -----------
214  if (topic_selected.find(topic_name) == topic_selected.end())
215  {
216  continue;
217  }
218  //----- parse! -----------
219  double timestamp = msg_timestamp;
220  MessageRef msg_ref(msg->serialized_data->buffer, msg->serialized_data->buffer_length);
221  parser.parseMessage(topic_name, msg_ref, timestamp);
222 
223  //---- save msg reference in PlotAny ----
224  auto data_point = PJ::PlotDataAny::Point(timestamp, std::any(msg));
225  plot_consecutive.pushBack(data_point);
226 
227  auto plot_pair = plot_map.user_defined.find(topic_name);
228  if (plot_pair == plot_map.user_defined.end())
229  {
230  plot_pair = plot_map.addUserDefined(topic_name);
231  }
232  PJ::PlotDataAny& plot_raw = plot_pair->second;
233  plot_raw.pushBack(data_point);
234  }
235 
236  auto now = std::chrono::high_resolution_clock::now();
237  double diff = std::chrono::duration_cast<std::chrono::milliseconds>(now - time_prev).count();
238 
239  qDebug() << "The rosbag loaded the data in " << diff << " milliseconds";
240 
242  return true;
243 }
244 
245 bool DataLoadROS2::xmlSaveState(QDomDocument& doc, QDomElement& plugin_elem) const
246 {
247  _config.xmlSaveState(doc, plugin_elem);
248  return true;
249 }
250 
251 bool DataLoadROS2::xmlLoadState(const QDomElement& parent_element)
252 {
253  _config.xmlLoadState(parent_element);
254  return true;
255 }
256 
258 {
259  QSettings settings;
260  _config.saveToSettings(settings, "DataLoadROS2");
261 }
262 
264 {
265  QSettings settings;
266  _config.loadFromSettings(settings, "DataLoadROS2");
267 }
void xmlLoadState(const QDomElement &parent_element)
void xmlSaveState(QDomDocument &doc, QDomElement &plugin_elem) const
std::vector< const char * > _extensions
Definition: dataload_ros2.h:41
type
void loadDefaultSettings()
QStringList selected_datasources
void registerMessageType(const std::string &topic_name, const std::string &topic_type)
Definition: ros2_parser.cpp:81
topic
std::string name
Definition: ros2_parser.h:21
std::shared_ptr< rosbag2_cpp::readers::SequentialReader > _bag_reader
Definition: dataload_ros2.h:39
constexpr auto count() -> size_t
virtual const std::vector< const char * > & compatibleFileExtensions() const override
AnySeriesMap::iterator addUserDefined(const std::string &name, PlotGroup::Ptr group={})
virtual bool xmlSaveState(QDomDocument &doc, QDomElement &parent_element) const override
bool parseMessage(const std::string &topic_name, MessageRef serialized_msg, double &timestamp)
void saveToSettings(QSettings &setting, QString prefix) const
typename PlotDataBase< double, Value >::Point Point
void saveDefaultSettings()
void pushBack(const Point &p) override
std::string type
Definition: ros2_parser.h:22
parser
AnySeriesMap user_defined
QDomDocument plugin_config
PJ::RosParserConfig getResult() const
virtual bool readDataFromFile(PJ::FileLoadInfo *fileload_info, PJ::PlotDataMapRef &destination) override
RosParserConfig _config
Definition: dataload_ros2.h:43
virtual bool xmlLoadState(const QDomElement &parent_element) override
void loadFromSettings(const QSettings &settings, QString prefix)
const rosidl_message_type_support_t * type_support
Definition: ros2_parser.h:23
void setConfig(const RosParserConfig &config)
msg


plotjuggler_ros
Author(s): Davide Faconti
autogenerated on Fri Jun 23 2023 02:28:03