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


plotjuggler_ros
Author(s): Davide Faconti
autogenerated on Wed Feb 21 2024 03:22:55