g2o
Loading...
Searching...
No Matches
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
29#include <cassert>
30#include <fstream>
31#include <iostream>
32
33#include "g2o/core/factory.h"
39using namespace std;
40
41namespace g2o {
42
43const int Gm2dlIO::ID_LASERPOSE = numeric_limits<int>::max();
44const int Gm2dlIO::ID_ODOMCALIB = numeric_limits<int>::max() - 1;
45
46bool Gm2dlIO::readGm2dl(const std::string& filename, SparseOptimizer& optimizer,
47 bool overrideCovariances) {
48 optimizer.clear();
49 ifstream is(filename.c_str());
50 if (!is.good()) return false;
51
52 bool laserOffsetInitDone = false;
53 VertexSE2* laserOffset = new VertexSE2;
54 // laserOffset->fixed() = true;
55 laserOffset->setId(ID_LASERPOSE);
56 if (!optimizer.addVertex(laserOffset)) {
57 cerr << "Unable to add laser offset" << endl;
58 return false;
59 }
60
61 // parse the GM2DL file an extract the vertices, edges, and the laser data
62 stringstream currentLine;
63 VertexSE2* previousVertex = 0;
64 while (1) {
65 int bytesRead = readLine(is, currentLine);
66 if (bytesRead == -1) break;
67 string tag;
68 currentLine >> tag;
69 if (tag == "VERTEX" || tag == "VERTEX2" || tag == "VERTEX_SE2") {
70 int id;
71 Eigen::Vector3d p;
72 currentLine >> id >> p.x() >> p.y() >> p.z();
73 // adding the robot pose
74 VertexSE2* v = new VertexSE2;
75 v->setId(id);
76 // cerr << "Read vertex id " << id << endl;
77 if (!optimizer.addVertex(v)) {
78 cerr << "vertex " << id << " is already in the graph, reassigning "
79 << endl;
80 delete v;
81 v = dynamic_cast<VertexSE2*>(optimizer.vertex(id));
82 assert(v);
83 }
84 v->setEstimate(p);
85 previousVertex = v;
86
87 } else if (tag == "EDGE" || tag == "EDGE2" || tag == "EDGE_SE2") {
88 if (!laserOffsetInitDone) {
89 cerr << "Error: need laser offset" << endl;
90 return false;
91 }
92 int id1, id2;
94 Eigen::Vector3d p;
95 Eigen::Matrix3d& m = e->information();
96 currentLine >> id1 >> id2 >> p.x() >> p.y() >> p.z();
97 if (overrideCovariances) {
98 m = Eigen::Matrix3d::Identity();
99 } else {
100 if (tag == "EDGE_SE2")
101 currentLine >> m(0, 0) >> m(0, 1) >> m(0, 2) >> m(1, 1) >> m(1, 2) >>
102 m(2, 2);
103 else // old stupid order of the information matrix
104 currentLine >> m(0, 0) >> m(0, 1) >> m(1, 1) >> m(2, 2) >> m(0, 2) >>
105 m(1, 2);
106 m(1, 0) = m(0, 1);
107 m(2, 0) = m(0, 2);
108 m(2, 1) = m(1, 2);
109 }
110 previousVertex = 0;
111 VertexSE2* v1 = dynamic_cast<VertexSE2*>(optimizer.vertex(id1));
112 VertexSE2* v2 = dynamic_cast<VertexSE2*>(optimizer.vertex(id2));
113 if (!v1) {
114 cerr << "vertex " << id1 << " is not existing, cannot add edge (" << id1
115 << "," << id2 << ")" << endl;
116 delete e;
117 continue;
118 }
119 if (!v2) {
120 cerr << "vertex " << id2 << " is not existing, cannot add edge (" << id1
121 << "," << id2 << ")" << endl;
122 delete e;
123 continue;
124 }
125
126 // if (0)
127 // if (abs(id1 - id2) != 1)
128 // m *= 1e-6;
129
130 // TODO transform measurement covariance by considering the laserOffset to
131 // measurement between the lasers
132 SE2 transf;
133 transf.fromVector(p);
134 e->setMeasurement(laserOffset->estimate().inverse() * transf *
135 laserOffset->estimate());
136 // e->inverseMeasurement() = e->measurement().inverse();
137
138 e->setVertex(0, v1);
139 e->setVertex(1, v2);
140 e->setVertex(2, laserOffset);
141 if (!optimizer.addEdge(e)) {
142 cerr << "error in adding edge " << id1 << "," << id2 << endl;
143 delete e;
144 }
145 // cerr << PVAR(e->inverseMeasurement().toVector().transpose()) << endl;
146 // cerr << PVAR(e->information()) << endl;
147
148 } else if (tag == "ROBOTLASER1") {
149 if (previousVertex) {
150 RobotLaser* rl2 = new RobotLaser;
151 rl2->read(currentLine);
152 if (!laserOffsetInitDone) {
153 laserOffsetInitDone = true;
154 // cerr << "g2o Laseroffset is " <<
155 // rl2->laserParams().laserPose.toVector().transpose() << endl;
156 laserOffset->setEstimate(rl2->laserParams().laserPose);
157 }
158 previousVertex->setUserData(rl2);
159 previousVertex = 0;
160 }
161 }
162 }
163
164 return true;
165}
166
167bool Gm2dlIO::writeGm2dl(const std::string& filename,
168 const SparseOptimizer& optimizer) {
169 ofstream fout(filename.c_str());
170 if (!fout.good()) {
171 return false;
172 }
173 Factory* factory = Factory::instance();
174
175 for (SparseOptimizer::VertexIDMap::const_iterator it =
176 optimizer.vertices().begin();
177 it != optimizer.vertices().end(); ++it) {
179 static_cast<OptimizableGraph::Vertex*>(it->second);
180 fout << "VERTEX2 " << v->id() << " ";
181 v->write(fout);
182 fout << endl;
183 HyperGraph::Data* data = v->userData();
184 if (data) { // writing the data via the factory
185 string tag = factory->tag(data);
186 if (tag.size() > 0) {
187 fout << tag << " ";
188 data->write(fout);
189 fout << endl;
190 }
191 }
192 }
193
194 OptimizableGraph::EdgeContainer edgesToSave; // sorting edges to have them in
195 // the order of insertion again
196 for (HyperGraph::EdgeSet::const_iterator it = optimizer.edges().begin();
197 it != optimizer.edges().end(); ++it) {
198 const OptimizableGraph::Edge* e =
199 static_cast<const OptimizableGraph::Edge*>(*it);
200 edgesToSave.push_back(const_cast<OptimizableGraph::Edge*>(e));
201 }
202 sort(edgesToSave.begin(), edgesToSave.end(),
204
205 for (OptimizableGraph::EdgeContainer::const_iterator it = edgesToSave.begin();
206 it != edgesToSave.end(); ++it) {
207 OptimizableGraph::Edge* e = *it;
208 EdgeSE2SensorCalib* calibEdge = dynamic_cast<EdgeSE2SensorCalib*>(e);
209 if (calibEdge) {
210 // write back in the gm2dl format
211 fout << "EDGE2 " << calibEdge->vertex(0)->id() << " "
212 << calibEdge->vertex(1)->id();
213 Eigen::Vector3d meas = calibEdge->measurement().toVector();
214 fout << " " << meas.x() << " " << meas.y() << " " << meas.z();
215 const Eigen::Matrix3d& m = calibEdge->information();
216 fout << " " << m(0, 0) << " " << m(0, 1) << " " << m(1, 1) << " "
217 << m(2, 2) << " " << m(0, 2) << " " << m(1, 2);
218 fout << endl;
219 } else {
220 // cerr << "Strange Edge Type: " << factory->tag(e) << endl;
221 }
222 }
223
224 return fout.good();
225}
226
228 VertexSE2* laserOffset =
229 dynamic_cast<VertexSE2*>(optimizer.vertex(ID_LASERPOSE));
230 if (!laserOffset) {
231 cerr << "Laser offset not found" << endl;
232 return false;
233 }
234
235 for (SparseOptimizer::VertexIDMap::const_iterator it =
236 optimizer.vertices().begin();
237 it != optimizer.vertices().end(); ++it) {
238 VertexSE2* v = dynamic_cast<VertexSE2*>(it->second);
239 if (!v) continue;
240 if (v->id() == ID_LASERPOSE) continue;
241 RobotLaser* robotLaser = dynamic_cast<RobotLaser*>(v->userData());
242 if (robotLaser) { // writing the data via the factory
243 robotLaser->setOdomPose(v->estimate());
244 LaserParameters params = robotLaser->laserParams();
245 params.laserPose = laserOffset->estimate();
246 robotLaser->setLaserParams(params);
247 }
248 }
249 return true;
250}
251
252int Gm2dlIO::readRobotLaser(const std::string& filename, DataQueue& queue) {
253 ifstream is(filename.c_str());
254 if (!is.good()) return false;
255
256 int cnt = 0;
257
258 // parse the GM2DL file and extract the vertices, edges, and the laser data
259 stringstream currentLine;
260 while (1) {
261 int bytesRead = readLine(is, currentLine);
262 if (bytesRead == -1) break;
263 string tag;
264 currentLine >> tag;
265 if (tag == "ROBOTLASER1") {
266 RobotLaser* rl2 = new RobotLaser;
267 rl2->read(currentLine);
268 queue.add(rl2);
269 cnt++;
270 }
271 }
272 return cnt;
273}
274
275} // namespace g2o
EIGEN_STRONG_INLINE const Measurement & measurement() const
accessor functions for the measurement represented by the edge
Definition base_edge.h:119
EIGEN_STRONG_INLINE const InformationType & information() const
information matrix of the constraint
Definition base_edge.h:107
const EstimateType & estimate() const
return the current estimate of the vertex
void setEstimate(const EstimateType &et)
set the estimate for the vertex also calls updateCache()
a simple queue to store data and retrieve based on a timestamp
Definition data_queue.h:41
void add(RobotData *rd)
scanmatch measurement that also calibrates an offset for the laser
void setMeasurement(const SE2 &m)
create vertices and edges based on TAGs in, for example, a file
Definition factory.h:48
static Factory * instance()
return the instance
Definition factory.cpp:46
const std::string & tag(const HyperGraph::HyperGraphElement *v) const
return the TAG given a vertex
Definition factory.cpp:138
static bool readGm2dl(const std::string &filename, SparseOptimizer &optimizer, bool overrideCovariances=false)
Definition gm2dl_io.cpp:46
static const int ID_LASERPOSE
Definition gm2dl_io.h:47
static const int ID_ODOMCALIB
Definition gm2dl_io.h:48
static int readRobotLaser(const std::string &filename, DataQueue &queue)
Definition gm2dl_io.cpp:252
static bool updateLaserData(SparseOptimizer &optimizer)
Definition gm2dl_io.cpp:227
static bool writeGm2dl(const std::string &filename, const SparseOptimizer &optimizer)
Definition gm2dl_io.cpp:167
const Data * userData() const
the user data associated with this vertex
data packet for a vertex. Extend this class to store in the vertices the potential additional informa...
Definition hyper_graph.h:93
virtual bool write(std::ostream &os) const =0
write the data to a stream
void setVertex(size_t i, Vertex *v)
const Vertex * vertex(size_t i) const
int id() const
returns the id
const EdgeSet & edges() const
const VertexIDMap & vertices() const
A general case Vertex for optimization.
virtual bool write(std::ostream &os) const =0
write the vertex to a stream
void setLaserParams(const LaserParameters &laserParams)
Definition raw_laser.cpp:80
const LaserParameters & laserParams() const
the parameters of the laser
Definition raw_laser.h:71
laser measurement obtained by a robot
Definition robot_laser.h:43
virtual bool read(std::istream &is)
read the data from a stream
void setOdomPose(const SE2 &odomPose)
represent SE2
Definition se2.h:43
SE2 inverse() const
invert :-)
Definition se2.h:83
void fromVector(const Vector3 &v)
assign from a 3D vector (x, y, theta)
Definition se2.h:102
2D pose Vertex, (x,y,theta)
Definition vertex_se2.h:41
int readLine(std::istream &is, std::stringstream &currentLine)
Definition jet.h:876
parameters for a 2D range finder
order edges based on the internal ID, which is assigned to the edge in addEdge()
std::vector< OptimizableGraph::Edge * > EdgeContainer
vector container for edges
virtual bool addEdge(HyperGraph::Edge *e)
virtual bool addVertex(HyperGraph::Vertex *v, Data *userData)
Vertex * vertex(int id)
returns the vertex number id appropriately casted