g2o
Loading...
Searching...
No Matches
Functions | Variables
sclam_odom_laser.cpp File Reference
#include <cassert>
#include <csignal>
#include <fstream>
#include <iostream>
#include <map>
#include "g2o/core/hyper_dijkstra.h"
#include "g2o/core/sparse_optimizer.h"
#include "g2o/stuff/color_macros.h"
#include "g2o/stuff/command_args.h"
#include "g2o/stuff/filesys_tools.h"
#include "g2o/stuff/macros.h"
#include "g2o/stuff/string_tools.h"
#include "g2o/stuff/timeutil.h"
#include "g2o/types/data/data_queue.h"
#include "g2o/types/data/robot_laser.h"
#include "g2o/types/sclam2d/odometry_measurement.h"
#include "g2o/types/sclam2d/vertex_odom_differential_params.h"
#include "g2o/types/slam2d/vertex_se2.h"
#include "gm2dl_io.h"
#include "sclam_helpers.h"
Include dependency graph for sclam_odom_laser.cpp:

Go to the source code of this file.

Functions

void sigquit_handler (int sig)
 
int main (int argc, char **argv)
 

Variables

static bool hasToStop = false
 

Function Documentation

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 66 of file sclam_odom_laser.cpp.

66 {
67 bool fixLaser;
68 int maxIterations;
69 bool verbose;
70 string inputFilename;
71 string outputfilename;
72 string rawFilename;
73 string odomTestFilename;
74 string dumpGraphFilename;
75 // command line parsing
76 CommandArgs commandLineArguments;
77 commandLineArguments.param("i", maxIterations, 10, "perform n iterations");
78 commandLineArguments.param("v", verbose, false,
79 "verbose output of the optimization process");
80 commandLineArguments.param("o", outputfilename, "",
81 "output final version of the graph");
82 commandLineArguments.param("test", odomTestFilename, "",
83 "apply odometry calibration to some test data");
84 commandLineArguments.param("dump", dumpGraphFilename, "",
85 "write the graph to the disk");
86 commandLineArguments.param("fixLaser", fixLaser, false,
87 "keep the laser offset fixed during optimization");
88 commandLineArguments.paramLeftOver("gm2dl-input", inputFilename, "",
89 "gm2dl file which will be processed");
90 commandLineArguments.paramLeftOver("raw-log", rawFilename, "",
91 "raw log file containing the odometry");
92
93 commandLineArguments.parseArgs(argc, argv);
94
95 SparseOptimizer optimizer;
96 optimizer.setVerbose(verbose);
97 optimizer.setForceStopFlag(&hasToStop);
98
99 allocateSolverForSclam(optimizer);
100
101 // loading
102 if (!Gm2dlIO::readGm2dl(inputFilename, optimizer, false)) {
103 cerr << "Error while loading gm2dl file" << endl;
104 }
105 DataQueue robotLaserQueue;
106 int numLaserOdom = Gm2dlIO::readRobotLaser(rawFilename, robotLaserQueue);
107 if (numLaserOdom == 0) {
108 cerr << "No raw information read" << endl;
109 return 0;
110 }
111 cerr << "Read " << numLaserOdom << " laser readings from file" << endl;
112
113 bool gaugeFreedom = optimizer.gaugeFreedom();
114
115 OptimizableGraph::Vertex* gauge = optimizer.findGauge();
116 if (gaugeFreedom) {
117 if (!gauge) {
118 cerr << "# cannot find a vertex to fix in this thing" << endl;
119 return 2;
120 } else {
121 cerr << "# graph is fixed by node " << gauge->id() << endl;
122 gauge->setFixed(true);
123 }
124 } else {
125 cerr << "# graph is fixed by priors" << endl;
126 }
127
128 addOdometryCalibLinksDifferential(optimizer, robotLaserQueue);
129
130 // sanity check
131 HyperDijkstra d(&optimizer);
133 d.shortestPaths(gauge, &f);
134 // cerr << PVAR(d.visited().size()) << endl;
135
136 if (d.visited().size() != optimizer.vertices().size()) {
137 cerr << CL_RED("Warning: d.visited().size() != optimizer.vertices().size()")
138 << endl;
139 cerr << "visited: " << d.visited().size() << endl;
140 cerr << "vertices: " << optimizer.vertices().size() << endl;
141 if (1)
142 for (SparseOptimizer::VertexIDMap::const_iterator it =
143 optimizer.vertices().begin();
144 it != optimizer.vertices().end(); ++it) {
146 static_cast<OptimizableGraph::Vertex*>(it->second);
147 if (d.visited().count(v) == 0) {
148 cerr << "\t unvisited vertex " << it->first << " "
149 << static_cast<void*>(v) << endl;
150 v->setFixed(true);
151 }
152 }
153 }
154
155 for (SparseOptimizer::VertexIDMap::const_iterator it =
156 optimizer.vertices().begin();
157 it != optimizer.vertices().end(); ++it) {
159 static_cast<OptimizableGraph::Vertex*>(it->second);
160 if (v->fixed()) {
161 cerr << "\t fixed vertex " << it->first << endl;
162 }
163 }
164
165 VertexSE2* laserOffset =
166 dynamic_cast<VertexSE2*>(optimizer.vertex(Gm2dlIO::ID_LASERPOSE));
167 VertexOdomDifferentialParams* odomParamsVertex =
168 dynamic_cast<VertexOdomDifferentialParams*>(
169 optimizer.vertex(Gm2dlIO::ID_ODOMCALIB));
170
171 if (fixLaser) {
172 cerr << "Fix position of the laser offset" << endl;
173 laserOffset->setFixed(true);
174 }
175
176 signal(SIGINT, sigquit_handler);
177 cerr << "Doing full estimation" << endl;
178 optimizer.initializeOptimization();
179 optimizer.computeActiveErrors();
180 cerr << "Initial chi2 = " << FIXED(optimizer.chi2()) << endl;
181
182 int i = optimizer.optimize(maxIterations);
183 if (maxIterations > 0 && !i) {
184 cerr << "optimize failed, result might be invalid" << endl;
185 }
186
187 if (laserOffset) {
188 cerr << "Calibrated laser offset (x, y, theta):"
189 << laserOffset->estimate().toVector().transpose() << endl;
190 }
191
192 if (odomParamsVertex) {
193 cerr << "Odometry parameters (scaling factors (v_l, v_r, b)): "
194 << odomParamsVertex->estimate().transpose() << endl;
195 }
196
197 cerr << "vertices: " << optimizer.vertices().size() << endl;
198 cerr << "edges: " << optimizer.edges().size() << endl;
199
200 if (dumpGraphFilename.size() > 0) {
201 cerr << "Writing " << dumpGraphFilename << " ... ";
202 optimizer.save(dumpGraphFilename.c_str());
203 cerr << "done." << endl;
204 }
205
206 // optional input of a separate file for applying the odometry calibration
207 if (odomTestFilename.size() > 0) {
208 DataQueue testRobotLaserQueue;
209 int numTestOdom =
210 Gm2dlIO::readRobotLaser(odomTestFilename, testRobotLaserQueue);
211 if (numTestOdom == 0) {
212 cerr << "Unable to read test data" << endl;
213 } else {
214 ofstream rawStream("odometry_raw.txt");
215 ofstream calibratedStream("odometry_calibrated.txt");
216 const Vector3d& odomCalib =
217 odomParamsVertex ? odomParamsVertex->estimate() : Vector3d::Ones();
218 RobotLaser* prev = dynamic_cast<RobotLaser*>(
219 testRobotLaserQueue.buffer().begin()->second);
220 SE2 prevCalibratedPose = prev->odomPose();
221
222 for (DataQueue::Buffer::const_iterator it =
223 testRobotLaserQueue.buffer().begin();
224 it != testRobotLaserQueue.buffer().end(); ++it) {
225 RobotLaser* cur = dynamic_cast<RobotLaser*>(it->second);
226 assert(cur);
227
228 double dt = cur->timestamp() - prev->timestamp();
229 SE2 motion = prev->odomPose().inverse() * cur->odomPose();
230
231 // convert to velocity Measurement
232 MotionMeasurement motionMeasurement(motion.translation().x(),
233 motion.translation().y(),
234 motion.rotation().angle(), dt);
235 VelocityMeasurement velocityMeasurement =
236 OdomConvert::convertToVelocity(motionMeasurement);
237
238 // apply calibration
239 VelocityMeasurement calibratedVelocityMeasurement = velocityMeasurement;
240 calibratedVelocityMeasurement.setVl(odomCalib(0) *
241 calibratedVelocityMeasurement.vl());
242 calibratedVelocityMeasurement.setVr(odomCalib(1) *
243 calibratedVelocityMeasurement.vr());
245 calibratedVelocityMeasurement, odomCalib(2));
246
247 // combine calibrated odometry with the previous pose
248 SE2 remappedOdom;
249 remappedOdom.fromVector(mm.measurement());
250 SE2 calOdomPose = prevCalibratedPose * remappedOdom;
251
252 // write output
253 rawStream << prev->odomPose().translation().x() << " "
254 << prev->odomPose().translation().y() << " "
255 << prev->odomPose().rotation().angle() << endl;
256 calibratedStream << calOdomPose.translation().x() << " "
257 << calOdomPose.translation().y() << " "
258 << calOdomPose.rotation().angle() << endl;
259
260 prevCalibratedPose = calOdomPose;
261 prev = cur;
262 }
263 }
264 }
265
266 if (outputfilename.size() > 0) {
267 Gm2dlIO::updateLaserData(optimizer);
268 cerr << "Writing " << outputfilename << " ... ";
269 bool writeStatus = Gm2dlIO::writeGm2dl(outputfilename, optimizer);
270 cerr << (writeStatus ? "done." : "failed") << endl;
271 }
272
273 return 0;
274}
const EstimateType & estimate() const
return the current estimate of the vertex
Command line parsing of argc and argv.
bool parseArgs(int argc, char **argv, bool exitOnError=true)
void paramLeftOver(const std::string &name, std::string &p, const std::string &defValue, const std::string &desc, bool optional=false)
void param(const std::string &name, bool &p, bool defValue, const std::string &desc)
a simple queue to store data and retrieve based on a timestamp
Definition data_queue.h:41
const Buffer & buffer() const
Definition data_queue.h:53
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
int id() const
returns the id
const EdgeSet & edges() const
const VertexIDMap & vertices() const
A 2D odometry measurement expressed as a transformation.
const Vector3 & measurement() const
static VelocityMeasurement convertToVelocity(const MotionMeasurement &m)
static MotionMeasurement convertToMotion(const VelocityMeasurement &vi, double l=1.0)
A general case Vertex for optimization.
bool fixed() const
true => this node is fixed during the optimization
void setFixed(bool fixed)
true => this node should be considered fixed during the optimization
double timestamp() const
Definition robot_data.h:46
laser measurement obtained by a robot
Definition robot_laser.h:43
const SE2 & odomPose() const
Definition robot_laser.h:53
represent SE2
Definition se2.h:43
const Vector2 & translation() const
translational component
Definition se2.h:57
Vector3 toVector() const
convert to a 3D vector (x, y, theta)
Definition se2.h:105
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
const Rotation2D & rotation() const
rotational component
Definition se2.h:61
int optimize(int iterations, bool online=false)
void setForceStopFlag(bool *flag)
void setVerbose(bool verbose)
virtual bool initializeOptimization(HyperGraph::EdgeSet &eset)
virtual Vertex * findGauge()
finds a gauge in the graph to remove the undefined dof.
velocity measurement of a differential robot
2D pose Vertex, (x,y,theta)
Definition vertex_se2.h:41
#define CL_RED(s)
void addOdometryCalibLinksDifferential(SparseOptimizer &optimizer, const DataQueue &odomData)
void allocateSolverForSclam(SparseOptimizer &optimizer, bool levenberg)
void sigquit_handler(int sig)
static bool hasToStop
virtual bool save(std::ostream &os, int level=0) const
save the graph to a stream. Again uses the Factory system.
double chi2() const
returns the chi2 of the current configuration
Vertex * vertex(int id)
returns the vertex number id appropriately casted

References g2o::addOdometryCalibLinksDifferential(), g2o::allocateSolverForSclam(), g2o::DataQueue::buffer(), g2o::OptimizableGraph::chi2(), CL_RED, g2o::SparseOptimizer::computeActiveErrors(), g2o::OdomConvert::convertToMotion(), g2o::OdomConvert::convertToVelocity(), g2o::HyperGraph::edges(), g2o::BaseVertex< D, T >::estimate(), g2o::SparseOptimizer::findGauge(), g2o::OptimizableGraph::Vertex::fixed(), g2o::SE2::fromVector(), g2o::SparseOptimizer::gaugeFreedom(), hasToStop, g2o::HyperGraph::Vertex::id(), g2o::Gm2dlIO::ID_LASERPOSE, g2o::Gm2dlIO::ID_ODOMCALIB, g2o::SparseOptimizer::initializeOptimization(), g2o::SE2::inverse(), g2o::MotionMeasurement::measurement(), g2o::RobotLaser::odomPose(), g2o::SparseOptimizer::optimize(), g2o::CommandArgs::param(), g2o::CommandArgs::paramLeftOver(), g2o::CommandArgs::parseArgs(), g2o::Gm2dlIO::readGm2dl(), g2o::Gm2dlIO::readRobotLaser(), g2o::SE2::rotation(), g2o::OptimizableGraph::save(), g2o::OptimizableGraph::Vertex::setFixed(), g2o::SparseOptimizer::setForceStopFlag(), g2o::SparseOptimizer::setVerbose(), g2o::VelocityMeasurement::setVl(), g2o::VelocityMeasurement::setVr(), g2o::HyperDijkstra::shortestPaths(), sigquit_handler(), g2o::RobotData::timestamp(), g2o::SE2::toVector(), g2o::SE2::translation(), g2o::Gm2dlIO::updateLaserData(), g2o::OptimizableGraph::vertex(), g2o::HyperGraph::vertices(), g2o::HyperDijkstra::visited(), g2o::VelocityMeasurement::vl(), g2o::VelocityMeasurement::vr(), and g2o::Gm2dlIO::writeGm2dl().

◆ sigquit_handler()

void sigquit_handler ( int  sig)

Definition at line 55 of file sclam_odom_laser.cpp.

55 {
56 if (sig == SIGINT) {
57 hasToStop = true;
58 static int cnt = 0;
59 if (cnt++ == 2) {
60 cerr << " forcing exit" << endl;
61 exit(1);
62 }
63 }
64}

References hasToStop.

Referenced by main().

Variable Documentation

◆ hasToStop

bool hasToStop = false
static

Definition at line 53 of file sclam_odom_laser.cpp.

Referenced by main(), and sigquit_handler().