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 "dialog_with_itemlist.h"
21 
23 {
24  _extensions.push_back("bag");
25  QSettings settings;
26  _config.loadFromSettings(settings, "DataLoadROS");
27 }
28 
30 {
31 }
32 
33 void StrCat(const std::string& a, const std::string& b, std::string& out)
34 {
35  out.clear();
36  out.reserve(a.size() + b.size());
37  out.assign(a);
38  out.append(b);
39 }
40 
41 const std::vector<const char*>& DataLoadROS::compatibleFileExtensions() const
42 {
43  return _extensions;
44 }
45 
46 std::vector<std::pair<QString, QString>>
48 {
49  std::vector<std::pair<QString, QString>> all_topics;
50  rosbag::View bag_view(*bag, ros::TIME_MIN, ros::TIME_MAX, true);
51 
52  bool ignoreAll = false;
53 
54  for (auto& conn : bag_view.getConnections())
55  {
56  const auto& topic = conn->topic;
57  const auto& md5sum = conn->md5sum;
58  const auto& datatype = conn->datatype;
59  const auto& definition = conn->msg_def;
60 
61  all_topics.push_back(std::make_pair(QString(topic.c_str()), QString(datatype.c_str())));
62  try
63  {
65  parser.addParser(topic, ros_parser);
67  }
68  catch (std::exception& ex)
69  {
70  // there was a problem with this topic
71  // a real life problem example can be found here:
72  // https://github.com/rosjava/rosjava_bootstrap/issues/16
73  all_topics.pop_back();
74 
75  if (ignoreAll)
76  {
77  // this is not the first error with this load and the
78  // user has accepted to ignore all errors
79  continue;
80  }
81 
82  // prompt user to abort or continue
83  QMessageBox msgBox(nullptr);
84  msgBox.setWindowTitle("ROS bag error");
85  msgBox.setText(QString("Topic ") + QString(topic.c_str()) + QString(": ") + QString(ex.what()));
86 
87  QPushButton* buttonCancel = msgBox.addButton(tr("Cancel"), QMessageBox::RejectRole);
88  QPushButton* buttonIgnore = msgBox.addButton(tr("Ignore"), QMessageBox::YesRole);
89  QPushButton* buttonIgnoreAll = msgBox.addButton(tr("Ignore all"), QMessageBox::AcceptRole);
90  msgBox.setDefaultButton(buttonIgnoreAll);
91  msgBox.exec();
92  if (msgBox.clickedButton() == buttonCancel)
93  {
94  // abort the file loading
95  throw;
96  }
97  if (msgBox.clickedButton() == buttonIgnoreAll)
98  {
99  // accept this and all future errors for this load
100  ignoreAll = true;
101  }
102  }
103  }
104  return all_topics;
105 }
106 
108 {
109  _plot_map = &plot_map;
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  PJ::CompositeParser ros_parser;
123  auto all_topics = getAllTopics(temp_bag.get(), ros_parser);
124 
125  //----------------------------------
126  // FIXME: we keep this here for backward compatibility
127  if (info->plugin_config.hasChildNodes())
128  {
129  xmlLoadState(info->plugin_config.firstChildElement());
130  }
131 
132  if (!info->plugin_config.hasChildNodes() || _config.topics.empty())
133  {
134  QSettings settings;
135  _config.loadFromSettings(settings, "DataLoadROS");
136 
137  DialogSelectRosTopics* dialog = new DialogSelectRosTopics(all_topics, _config);
138 
139  if (dialog->exec() != static_cast<int>(QDialog::Accepted))
140  {
141  return false;
142  }
143  _config = dialog->getResult();
144  }
145 
146  //--- Swith the previous bag with this one
147  // clean up previous MessageInstances
148  plot_map.user_defined.clear();
149  if (_bag)
150  {
151  _bag->close();
152  }
153  _bag = temp_bag;
154  //---------------------------------------
155 
156  {
157  QSettings settings;
158  _config.saveToSettings(settings, "DataLoadROS");
159  }
160 
161  ros_parser.setConfig(_config);
162 
163  //-----------------------------------
164  std::set<std::string> topic_selected;
165  for (const auto& topic : _config.topics)
166  {
167  topic_selected.insert(topic.toStdString());
168  }
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 
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  PJ::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  PJ::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 = PJ::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  PJ::PlotDataAny& plot_raw = plot_pair->second;
233  plot_raw.pushBack(data_point);
234  }
235 
236  qDebug() << "The loading operation took" << timer.elapsed() << "milliseconds";
237 
238  return true;
239 }
240 
241 bool DataLoadROS::xmlSaveState(QDomDocument& doc, QDomElement& plugin_elem) const
242 {
243  _config.xmlSaveState(doc, plugin_elem);
244  return true;
245 }
246 
247 bool DataLoadROS::xmlLoadState(const QDomElement& parent_element)
248 {
249  _config.xmlLoadState(parent_element);
250  return true;
251 }
252 
buffer::data
auto data() const FMT_NOEXCEPT -> const T *
ros::serialization::OStream
PJ::TimeseriesBase
md5sum
const char * md5sum()
rosbag::Bag
rosbag::View::size
uint32_t size()
DataLoadROS::xmlLoadState
virtual bool xmlLoadState(const QDomElement &parent_element) override
Definition: dataload_ros.cpp:247
DataLoadROS::_plot_map
PJ::PlotDataMapRef * _plot_map
Definition: dataload_ros.h:51
PJ::FileLoadInfo
DataLoadROS::_extensions
std::vector< const char * > _extensions
Definition: dataload_ros.h:45
PJ::RosParserConfig::saveToSettings
void saveToSettings(QSettings &setting, QString prefix) const
Definition: parser_configuration.cpp:58
definition
const char * definition()
rosbag::MessageInstance
PJ::TimeseriesBase::pushBack
void pushBack(const Point &p) override
PJ::CompositeParser::setConfig
void setConfig(const RosParserConfig &config)
Definition: parser_configuration.cpp:90
DataLoadROS::xmlSaveState
virtual bool xmlSaveState(QDomDocument &doc, QDomElement &parent_element) const override
Definition: dataload_ros.cpp:241
PJ::FileLoadInfo::plugin_config
QDomDocument plugin_config
parser
parser
RosIntrospectionFactory::registerMessage
static void registerMessage(const std::string &topic_name, const std::string &md5sum, const std::string &datatype, const std::string &definition)
Definition: shape_shifter_factory.hpp:44
buffer
dialog_select_ros_topics.h
DataLoadROS::getAllTopics
std::vector< std::pair< QString, QString > > getAllTopics(const rosbag::Bag *bag, PJ::CompositeParser &parser)
Definition: dataload_ros.cpp:47
DataLoadROS::_config
PJ::RosParserConfig _config
Definition: dataload_ros.h:47
rosbag::bagmode::Read
Read
rosbag::BagException
DialogSelectRosTopics
Definition: dialog_select_ros_topics.h:19
StrCat
void StrCat(const std::string &a, const std::string &b, std::string &out)
Definition: dataload_ros.cpp:33
topic
topic
out
std::add_lvalue_reference< decltype(std::declval< FormatContext >).out())>::type out
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
ros::TIME_MIN
const Time TIME_MIN(0, 1)
rosbag::View::getConnections
std::vector< const ConnectionInfo * > getConnections()
dataload_ros.h
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
view.h
PJ::CompositeParser::parseMessage
bool parseMessage(const std::string &topic_name, MessageRef serialized_msg, double &timestamp)
Definition: parser_configuration.cpp:102
rosbag::View
ros::TIME_MAX
const ROSTIME_DECL Time TIME_MAX
CreateParserROS
std::shared_ptr< PJ::MessageParser > CreateParserROS(const PJ::ParserFactories &factories, const std::string &topic_name, const std::string &type_name, const std::string &definition, PJ::PlotDataMapRef &data)
Definition: ros1_parser.h:7
DataLoadROS::compatibleFileExtensions
virtual const std::vector< const char * > & compatibleFileExtensions() const override
Definition: dataload_ros.cpp:41
DialogSelectRosTopics::getResult
PJ::RosParserConfig getResult() const
Definition: dialog_select_ros_topics.cpp:154
DataLoadROS::readDataFromFile
virtual bool readDataFromFile(PJ::FileLoadInfo *fileload_info, PJ::PlotDataMapRef &destination) override
Definition: dataload_ros.cpp:107
PJ::MessageRef
DataLoadROS::~DataLoadROS
virtual ~DataLoadROS() override
Definition: dataload_ros.cpp:29
datatype
const char * datatype()
PJ::PlotDataMapRef
shape_shifter_factory.hpp
PJ::PlotDataMapRef::user_defined
AnySeriesMap user_defined
dialog_with_itemlist.h
DataLoadROS::_bag
std::shared_ptr< rosbag::Bag > _bag
Definition: dataload_ros.h:42
PJ::RosParserConfig::topics
QStringList topics
Definition: parser_configuration.h:16
DataLoadROS::DataLoadROS
DataLoadROS()
Definition: dataload_ros.cpp:22
buffer::size
auto size() const FMT_NOEXCEPT -> size_t
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