dataload_ros.cpp
Go to the documentation of this file.
1 #include "dataload_ros.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 <QProcess>
11 #include <rosbag/view.h>
12 #include <QSettings>
13 #include <QElapsedTimer>
14 #include <condition_variable>
15 #include <functional>
16 #include <thread>
17 
20 #include "rule_editing.h"
21 #include "dialog_with_itemlist.h"
22 
23 DataLoadROS::DataLoadROS()
24 {
25  _extensions.push_back("bag");
26  QSettings settings;
27  _config.loadFromSettings(settings, "DataLoadROS");
28 }
29 
30 DataLoadROS::~DataLoadROS()
31 {
32 }
33 
34 void StrCat(const std::string& a, const std::string& b, std::string& out)
35 {
36  out.clear();
37  out.reserve(a.size() + b.size());
38  out.assign(a);
39  out.append(b);
40 }
41 
42 const std::vector<const char*>& DataLoadROS::compatibleFileExtensions() const
43 {
44  return _extensions;
45 }
46 
47 std::vector<std::pair<QString, QString>>
49 {
50  std::vector<std::pair<QString, QString>> all_topics;
51  rosbag::View bag_view(*bag, ros::TIME_MIN, ros::TIME_MAX, true);
52 
53  bool ignoreAll = false;
54 
55  for (auto& conn : bag_view.getConnections())
56  {
57  const auto& topic = conn->topic;
58  const auto& md5sum = conn->md5sum;
59  const auto& datatype = conn->datatype;
60  const auto& definition = conn->msg_def;
61 
62  all_topics.push_back(std::make_pair(QString(topic.c_str()), QString(datatype.c_str())));
63  try
64  {
66 
68  }
69  catch (std::exception& ex)
70  {
71  // there was a problem with this topic
72  // a real life problem example can be found here:
73  // https://github.com/rosjava/rosjava_bootstrap/issues/16
74  all_topics.pop_back();
75 
76  if (ignoreAll)
77  {
78  // this is not the first error with this load and the
79  // user has accepted to ignore all errors
80  continue;
81  }
82 
83  // prompt user to abort or continue
84  QMessageBox msgBox(nullptr);
85  msgBox.setWindowTitle("ROS bag error");
86  msgBox.setText(QString("Topic ") + QString(topic.c_str()) + QString(": ") + QString(ex.what()));
87 
88  QPushButton* buttonCancel = msgBox.addButton(tr("Cancel"), QMessageBox::RejectRole);
89  QPushButton* buttonIgnore = msgBox.addButton(tr("Ignore"), QMessageBox::YesRole);
90  QPushButton* buttonIgnoreAll = msgBox.addButton(tr("Ignore all"), QMessageBox::AcceptRole);
91  msgBox.setDefaultButton(buttonIgnoreAll);
92  msgBox.exec();
93  if (msgBox.clickedButton() == buttonCancel)
94  {
95  // abort the file loading
96  throw;
97  }
98  if (msgBox.clickedButton() == buttonIgnoreAll)
99  {
100  // accept this and all future errors for this load
101  ignoreAll = true;
102  }
103  }
104  }
105  return all_topics;
106 }
107 
109 {
110  auto temp_bag = std::make_shared<rosbag::Bag>();
111 
112  try
113  {
114  temp_bag->open(info->filename.toStdString(), rosbag::bagmode::Read);
115  }
116  catch (rosbag::BagException& ex)
117  {
118  QMessageBox::warning(nullptr, tr("Error"), QString("rosbag::open thrown an exception:\n") + QString(ex.what()));
119  return false;
120  }
121 
122  RosCompositeParser ros_parser(plot_map);
123  auto all_topics = getAllTopics(temp_bag.get(), ros_parser);
124 
125  //----------------------------------
126 
127  if (info->plugin_config.hasChildNodes())
128  {
129  xmlLoadState(info->plugin_config.firstChildElement());
130  }
131 
132  if (!info->selected_datasources.empty())
133  {
135  }
136  else
137  {
138  DialogSelectRosTopics* dialog = new DialogSelectRosTopics(all_topics, _config);
139 
140  if (dialog->exec() != static_cast<int>(QDialog::Accepted))
141  {
142  return false;
143  }
144  _config = dialog->getResult();
145  }
146 
147  //--- Swith the previous bag with this one
148  // clean up previous MessageInstances
149  plot_map.user_defined.clear();
150  if (_bag)
151  {
152  _bag->close();
153  }
154  _bag = temp_bag;
155  //---------------------------------------
156 
157  {
158  QSettings settings;
159  _config.saveToSettings(settings, "DataLoadROS");
160  }
161 
162  ros_parser.setConfig(_config);
163 
164  //-----------------------------------
165  std::set<std::string> topic_selected;
166  for (const auto& topic : _config.topics)
167  {
168  topic_selected.insert(topic.toStdString());
169  }
170 
171  QProgressDialog progress_dialog;
172  progress_dialog.setLabelText("Loading... please wait");
173  progress_dialog.setWindowModality(Qt::ApplicationModal);
174 
175  rosbag::View bag_view(*_bag);
176 
177  progress_dialog.setRange(0, bag_view.size() - 1);
178  progress_dialog.show();
179 
180  int msg_count = 0;
181 
182  QElapsedTimer timer;
183  timer.start();
184 
185  PlotDataAny& plot_consecutive = plot_map.addUserDefined("plotjuggler::rosbag1::consecutive_messages")->second;
186 
187  std::vector<uint8_t> buffer;
188 
189  for (const rosbag::MessageInstance& msg_instance : bag_view)
190  {
191  const std::string& topic_name = msg_instance.getTopic();
192  double msg_time = msg_instance.getTime().toSec();
193 
194  //----- skip not selected -----------
195  if (topic_selected.find(topic_name) == topic_selected.end())
196  {
197  continue;
198  }
199 
200  //------ progress dialog --------------
201  if (msg_count++ % 100 == 0)
202  {
203  progress_dialog.setValue(msg_count);
204  QApplication::processEvents();
205 
206  if (progress_dialog.wasCanceled())
207  {
208  return false;
209  }
210  }
211 
212  //----- parse! -----------
213  const size_t msg_size = msg_instance.size();
214  buffer.resize(msg_size);
215  ros::serialization::OStream stream(buffer.data(), msg_size);
216  msg_instance.write(stream);
217 
218  MessageRef msg_serialized(buffer.data(), buffer.size());
219 
220  double tmp_timestamp = msg_time;
221  ros_parser.parseMessage(topic_name, msg_serialized, tmp_timestamp);
222 
223  //------ save msg reference in PlotAny ----
224  auto data_point = PlotDataAny::Point(tmp_timestamp, std::any(msg_instance));
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  PlotDataAny& plot_raw = plot_pair->second;
233  plot_raw.pushBack(data_point);
234  }
235 
236  qDebug() << "The loading operation took" << timer.elapsed() << "milliseconds";
237 
239  return true;
240 }
241 
242 bool DataLoadROS::xmlSaveState(QDomDocument& doc, QDomElement& plugin_elem) const
243 {
244  _config.xmlSaveState(doc, plugin_elem);
245  return true;
246 }
247 
248 bool DataLoadROS::xmlLoadState(const QDomElement& parent_element)
249 {
250  _config.xmlLoadState(parent_element);
251  return true;
252 }
253 
void xmlLoadState(const QDomElement &parent_element)
void xmlSaveState(QDomDocument &doc, QDomElement &plugin_elem) const
std::vector< const char * > _extensions
Definition: dataload_ros.h:46
static void registerMessage(const std::string &topic_name, const std::string &md5sum, const std::string &datatype, const std::string &definition)
std::vector< const ConnectionInfo *> getConnections()
const Time TIME_MIN(0, 1)
QStringList selected_datasources
virtual bool xmlLoadState(const QDomElement &parent_element) override
void registerMessageType(const std::string &topic_name, const std::string &topic_type, const std::string &definition)
Definition: ros1_parser.cpp:94
topic
virtual bool xmlSaveState(QDomDocument &doc, QDomElement &parent_element) const override
uint32_t size()
const char * datatype()
RosParserConfig _config
Definition: dataload_ros.h:48
void StrCat(const std::string &a, const std::string &b, std::string &out)
virtual bool readDataFromFile(PJ::FileLoadInfo *fileload_info, PJ::PlotDataMapRef &destination) override
ROSTIME_DECL const Time TIME_MAX
AnySeriesMap::iterator addUserDefined(const std::string &name, PlotGroup::Ptr group={})
bool parseMessage(const std::string &topic_name, MessageRef serialized_msg, double &timestamp)
void saveToSettings(QSettings &setting, QString prefix) const
virtual const std::vector< const char * > & compatibleFileExtensions() const override
typename PlotDataBase< double, Value >::Point Point
void pushBack(const Point &p) override
std::shared_ptr< rosbag::Bag > _bag
Definition: dataload_ros.h:43
AnySeriesMap user_defined
const char * md5sum()
QDomDocument plugin_config
PJ::RosParserConfig getResult() const
const char * definition()
void loadFromSettings(const QSettings &settings, QString prefix)
void setConfig(const RosParserConfig &config)
std::vector< std::pair< QString, QString > > getAllTopics(const rosbag::Bag *bag, RosCompositeParser &parser)


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