g2o
gm2dl_io.cpp
Go to the documentation of this file.
1 // g2o - General Graph Optimization
2 // Copyright (C) 2011 R. Kuemmerle, G.Grisetti, W. Burgard
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
18 // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 #include "gm2dl_io.h"
28 
30 
32 #include "g2o/core/factory.h"
33 
36 
37 #include "g2o/stuff/string_tools.h"
38 
39 #include <fstream>
40 #include <iostream>
41 using namespace std;
42 
43 namespace g2o {
44 
45  const int Gm2dlIO::ID_LASERPOSE = numeric_limits<int>::max();
46  const int Gm2dlIO::ID_ODOMCALIB = numeric_limits<int>::max() - 1;
47 
48  bool Gm2dlIO::readGm2dl(const std::string& filename, SparseOptimizer& optimizer, bool overrideCovariances)
49  {
50  optimizer.clear();
51  ifstream is(filename.c_str());
52  if (! is.good())
53  return false;
54 
55  bool laserOffsetInitDone = false;
56  VertexSE2* laserOffset = new VertexSE2;
57  //laserOffset->fixed() = true;
58  laserOffset->setId(ID_LASERPOSE);
59  if (! optimizer.addVertex(laserOffset)) {
60  cerr << "Unable to add laser offset" << endl;
61  return false;
62  }
63 
64  // parse the GM2DL file an extract the vertices, edges, and the laser data
65  stringstream currentLine;
66  VertexSE2* previousVertex = 0;
67  while(1) {
68  int bytesRead = readLine(is, currentLine);
69  if (bytesRead == -1)
70  break;
71  string tag;
72  currentLine >> tag;
73  if (tag == "VERTEX" || tag == "VERTEX2" || tag == "VERTEX_SE2"){
74  int id;
75  Eigen::Vector3d p;
76  currentLine >> id >> p.x() >> p.y() >> p.z();
77  // adding the robot pose
78  VertexSE2* v = new VertexSE2;
79  v->setId(id);
80  //cerr << "Read vertex id " << id << endl;
81  if (! optimizer.addVertex(v)) {
82  cerr << "vertex " << id << " is already in the graph, reassigning "<< endl;
83  delete v;
84  v = dynamic_cast<VertexSE2*>(optimizer.vertex(id));
85  assert(v);
86  }
87  v->setEstimate(p);
88  previousVertex = v;
89 
90  } else if (tag == "EDGE" || tag == "EDGE2" || tag == "EDGE_SE2"){
91  if (! laserOffsetInitDone) {
92  cerr << "Error: need laser offset" << endl;
93  return false;
94  }
95  int id1, id2;
97  Eigen::Vector3d p;
98  Eigen::Matrix3d& m = e->information();
99  currentLine >> id1 >> id2 >> p.x() >> p.y() >> p.z();
100  if (overrideCovariances){
101  m = Eigen::Matrix3d::Identity();
102  } else {
103  if (tag == "EDGE_SE2")
104  currentLine >> m(0, 0) >> m(0, 1) >> m(0, 2) >> m(1, 1) >> m(1, 2) >> m(2, 2);
105  else // old stupid order of the information matrix
106  currentLine >> m(0, 0) >> m(0, 1) >> m(1, 1) >> m(2, 2) >> m(0, 2) >> m(1, 2);
107  m(1, 0) = m(0, 1);
108  m(2, 0) = m(0, 2);
109  m(2, 1) = m(1, 2);
110  }
111  previousVertex = 0;
112  VertexSE2* v1 = dynamic_cast<VertexSE2*>(optimizer.vertex(id1));
113  VertexSE2* v2 = dynamic_cast<VertexSE2*>(optimizer.vertex(id2));
114  if (! v1) {
115  cerr << "vertex " << id1 << " is not existing, cannot add edge (" << id1 << "," << id2 << ")" << endl;
116  delete e;
117  continue;
118  }
119  if (! v2) {
120  cerr << "vertex " << id2 << " is not existing, cannot add edge (" << id1 << "," << id2 << ")" << endl;
121  delete e;
122  continue;
123  }
124 
125  //if (0)
126  //if (abs(id1 - id2) != 1)
127  //m *= 1e-6;
128 
129  // TODO transform measurement covariance by considering the laserOffset to measurement between the lasers
130  SE2 transf; transf.fromVector(p);
131  e->setMeasurement(laserOffset->estimate().inverse() * transf * laserOffset->estimate());
132  //e->inverseMeasurement() = e->measurement().inverse();
133 
134  e->setVertex(0, v1);
135  e->setVertex(1, v2);
136  e->setVertex(2, laserOffset);
137  if (! optimizer.addEdge(e)){
138  cerr << "error in adding edge " << id1 << "," << id2 << endl;
139  delete e;
140  }
141  //cerr << PVAR(e->inverseMeasurement().toVector().transpose()) << endl;
142  //cerr << PVAR(e->information()) << endl;
143 
144  } else if (tag == "ROBOTLASER1") {
145  if (previousVertex) {
146  RobotLaser* rl2 = new RobotLaser;
147  rl2->read(currentLine);
148  if (! laserOffsetInitDone) {
149  laserOffsetInitDone = true;
150  //cerr << "g2o Laseroffset is " << rl2->laserParams().laserPose.toVector().transpose() << endl;
151  laserOffset->setEstimate(rl2->laserParams().laserPose);
152  }
153  previousVertex->setUserData(rl2);
154  previousVertex = 0;
155  }
156  }
157  }
158 
159  return true;
160  }
161 
162  bool Gm2dlIO::writeGm2dl(const std::string& filename, const SparseOptimizer& optimizer)
163  {
164  ofstream fout(filename.c_str());
165  if (! fout.good()) {
166  return false;
167  }
168  Factory* factory = Factory::instance();
169 
170  for (SparseOptimizer::VertexIDMap::const_iterator it = optimizer.vertices().begin(); it != optimizer.vertices().end(); ++it) {
171  OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(it->second);
172  fout << "VERTEX2 " << v->id() << " ";
173  v->write(fout);
174  fout << endl;
175  HyperGraph::Data* data = v->userData();
176  if (data) { // writing the data via the factory
177  string tag = factory->tag(data);
178  if (tag.size() > 0) {
179  fout << tag << " ";
180  data->write(fout);
181  fout << endl;
182  }
183  }
184  }
185 
186  OptimizableGraph::EdgeContainer edgesToSave; // sorting edges to have them in the order of insertion again
187  for (HyperGraph::EdgeSet::const_iterator it = optimizer.edges().begin(); it != optimizer.edges().end(); ++it) {
188  const OptimizableGraph::Edge* e = static_cast<const OptimizableGraph::Edge*>(*it);
189  edgesToSave.push_back(const_cast<OptimizableGraph::Edge*>(e));
190  }
191  sort(edgesToSave.begin(), edgesToSave.end(), OptimizableGraph::EdgeIDCompare());
192 
193  for (OptimizableGraph::EdgeContainer::const_iterator it = edgesToSave.begin(); it != edgesToSave.end(); ++it) {
194  OptimizableGraph::Edge* e = *it;
195  EdgeSE2SensorCalib* calibEdge = dynamic_cast<EdgeSE2SensorCalib*>(e);
196  if (calibEdge) {
197  // write back in the gm2dl format
198  fout << "EDGE2 " << calibEdge->vertex(0)->id() << " " << calibEdge->vertex(1)->id();
199  Eigen::Vector3d meas = calibEdge->measurement().toVector();
200  fout << " " << meas.x() << " " << meas.y() << " " << meas.z();
201  const Eigen::Matrix3d& m = calibEdge->information();
202  fout << " " << m(0, 0) << " " << m(0, 1) << " " << m(1, 1) << " "
203  << m(2, 2) << " " << m(0, 2) << " " << m(1, 2);
204  fout << endl;
205  } else {
206  //cerr << "Strange Edge Type: " << factory->tag(e) << endl;
207  }
208  }
209 
210  return fout.good();
211  }
212 
213  bool Gm2dlIO::updateLaserData(SparseOptimizer& optimizer)
214  {
215  VertexSE2* laserOffset = dynamic_cast<VertexSE2*>(optimizer.vertex(ID_LASERPOSE));
216  if (! laserOffset) {
217  cerr << "Laser offset not found" << endl;
218  return false;
219  }
220 
221  for (SparseOptimizer::VertexIDMap::const_iterator it = optimizer.vertices().begin(); it != optimizer.vertices().end(); ++it) {
222  VertexSE2* v = dynamic_cast<VertexSE2*>(it->second);
223  if (! v)
224  continue;
225  if (v->id() == ID_LASERPOSE)
226  continue;
227  RobotLaser* robotLaser = dynamic_cast<RobotLaser*>(v->userData());
228  if (robotLaser) { // writing the data via the factory
229  robotLaser->setOdomPose(v->estimate());
230  LaserParameters params = robotLaser->laserParams();
231  params.laserPose = laserOffset->estimate();
232  robotLaser->setLaserParams(params);
233  }
234  }
235  return true;
236  }
237 
238  int Gm2dlIO::readRobotLaser(const std::string& filename, DataQueue& queue)
239  {
240  ifstream is(filename.c_str());
241  if (! is.good())
242  return false;
243 
244  int cnt = 0;
245 
246  // parse the GM2DL file and extract the vertices, edges, and the laser data
247  stringstream currentLine;
248  while(1) {
249  int bytesRead = readLine(is, currentLine);
250  if (bytesRead == -1)
251  break;
252  string tag;
253  currentLine >> tag;
254  if (tag == "ROBOTLASER1") {
255  RobotLaser* rl2 = new RobotLaser;
256  rl2->read(currentLine);
257  queue.add(rl2);
258  cnt++;
259  }
260  }
261  return cnt;
262  }
263 
264 } // end namespace
void add(RobotData *rd)
Definition: data_queue.cpp:76
virtual bool write(std::ostream &os) const =0
write the vertex to a stream
virtual bool write(std::ostream &os) const =0
write the data to a stream
int id() const
returns the id
Definition: hyper_graph.h:148
const Vertex * vertex(size_t i) const
Definition: hyper_graph.h:186
data packet for a vertex. Extend this class to store in the vertices the potential additional informa...
Definition: hyper_graph.h:97
const Data * userData() const
the user data associated with this vertex
Definition: hyper_graph.h:126
Vector3D toVector() const
convert to a 3D vector (x, y, theta)
Definition: se2.h:108
scanmatch measurement that also calibrates an offset for the laser
laser measurement obtained by a robot
Definition: robot_laser.h:42
void setOdomPose(const SE2 &odomPose)
represent SE2
Definition: se2.h:40
2D pose Vertex, (x,y,theta)
Definition: vertex_se2.h:41
void setLaserParams(const LaserParameters &laserParams)
Definition: raw_laser.cpp:88
void setVertex(size_t i, Vertex *v)
Definition: hyper_graph.h:194
virtual bool read(std::istream &is)
read the data from a stream
Definition: robot_laser.cpp:50
const VertexIDMap & vertices() const
Definition: hyper_graph.h:225
Vertex * vertex(int id)
returns the vertex number id appropriately casted
virtual void setId(int id)
sets the id of the node in the graph be sure that the graph keeps consistent after changing the id ...
std::vector< OptimizableGraph::Edge * > EdgeContainer
vector container for edges
void setMeasurement(const SE2 &m)
const std::string & tag(const HyperGraph::HyperGraphElement *v) const
return the TAG given a vertex
Definition: factory.cpp:157
const EdgeSet & edges() const
Definition: hyper_graph.h:230
void fromVector(const Vector3D &v)
assign from a 3D vector (x, y, theta)
Definition: se2.h:103
create vertices and edges based on TAGs in, for example, a file
Definition: factory.h:49
int readLine(std::istream &is, std::stringstream &currentLine)
void setEstimate(const EstimateType &et)
set the estimate for the vertex also calls updateCache()
Definition: base_vertex.h:101
a simple queue to store data and retrieve based on a timestamp
Definition: data_queue.h:40
order edges based on the internal ID, which is assigned to the edge in addEdge()
A general case Vertex for optimization.
const LaserParameters & laserParams() const
the parameters of the laser
Definition: raw_laser.h:72
EIGEN_STRONG_INLINE const InformationType & information() const
information matrix of the constraint
Definition: base_edge.h:67
const EstimateType & estimate() const
return the current estimate of the vertex
Definition: base_vertex.h:99
SE2 inverse() const
invert :-)
Definition: se2.h:82
virtual bool addEdge(HyperGraph::Edge *e)
virtual bool addVertex(HyperGraph::Vertex *v, Data *userData)
EIGEN_STRONG_INLINE const Measurement & measurement() const
accessor functions for the measurement represented by the edge
Definition: base_edge.h:75
parameters for a 2D range finder