53 using namespace Eigen;
63 cerr <<
" forcing exit" << endl;
69 int main(
int argc,
char** argv)
75 string outputfilename;
77 string odomTestFilename;
78 string dumpGraphFilename;
81 commandLineArguments.
param(
"i", maxIterations, 10,
"perform n iterations");
82 commandLineArguments.
param(
"v", verbose,
false,
"verbose output of the optimization process");
83 commandLineArguments.
param(
"o", outputfilename,
"",
"output final version of the graph");
84 commandLineArguments.
param(
"test", odomTestFilename,
"",
"apply odometry calibration to some test data");
85 commandLineArguments.
param(
"dump", dumpGraphFilename,
"",
"write the graph to the disk");
86 commandLineArguments.
param(
"fixLaser", fixLaser,
false,
"keep the laser offset fixed during optimization");
87 commandLineArguments.
paramLeftOver(
"gm2dl-input", inputFilename,
"",
"gm2dl file which will be processed");
88 commandLineArguments.
paramLeftOver(
"raw-log", rawFilename,
"",
"raw log file containing the odometry");
90 commandLineArguments.
parseArgs(argc, argv);
99 if (! Gm2dlIO::readGm2dl(inputFilename, optimizer,
false)) {
100 cerr <<
"Error while loading gm2dl file" << endl;
103 int numLaserOdom = Gm2dlIO::readRobotLaser(rawFilename, robotLaserQueue);
104 if (numLaserOdom == 0) {
105 cerr <<
"No raw information read" << endl;
108 cerr <<
"Read " << numLaserOdom <<
" laser readings from file" << endl;
115 cerr <<
"# cannot find a vertex to fix in this thing" << endl;
118 cerr <<
"# graph is fixed by node " << gauge->
id() << endl;
122 cerr <<
"# graph is fixed by priors" << endl;
134 cerr <<
CL_RED(
"Warning: d.visited().size() != optimizer.vertices().size()") << endl;
135 cerr <<
"visited: " << d.
visited().size() << endl;
136 cerr <<
"vertices: " << optimizer.
vertices().size() << endl;
138 for (SparseOptimizer::VertexIDMap::const_iterator it = optimizer.
vertices().begin(); it != optimizer.
vertices().end(); ++it) {
140 if (d.
visited().count(v) == 0) {
141 cerr <<
"\t unvisited vertex " << it->first <<
" " << (
void*)v << endl;
147 for (SparseOptimizer::VertexIDMap::const_iterator it = optimizer.
vertices().begin(); it != optimizer.
vertices().end(); ++it) {
150 cerr <<
"\t fixed vertex " << it->first << endl;
158 cerr <<
"Fix position of the laser offset" << endl;
163 cerr <<
"Doing full estimation" << endl;
166 cerr <<
"Initial chi2 = " << FIXED(optimizer.
chi2()) << endl;
168 int i=optimizer.
optimize(maxIterations);
169 if (maxIterations > 0 && !i){
170 cerr <<
"optimize failed, result might be invalid" << endl;
174 cerr <<
"Calibrated laser offset (x, y, theta):" << laserOffset->
estimate().
toVector().transpose() << endl;
177 if (odomParamsVertex) {
178 cerr <<
"Odometry parameters (scaling factors (v_l, v_r, b)): " << odomParamsVertex->
estimate().transpose() << endl;
181 cerr <<
"vertices: " << optimizer.
vertices().size() << endl;
182 cerr <<
"edges: " << optimizer.
edges().size() << endl;
184 if (dumpGraphFilename.size() > 0) {
185 cerr <<
"Writing " << dumpGraphFilename <<
" ... ";
186 optimizer.
save(dumpGraphFilename.c_str());
187 cerr <<
"done." << endl;
191 if (odomTestFilename.size() > 0) {
194 int numTestOdom = Gm2dlIO::readRobotLaser(odomTestFilename, testRobotLaserQueue);
195 if (numTestOdom == 0) {
196 cerr <<
"Unable to read test data" << endl;
199 ofstream rawStream(
"odometry_raw.txt");
200 ofstream calibratedStream(
"odometry_calibrated.txt");
201 const Vector3d& odomCalib = odomParamsVertex->
estimate();
205 for (DataQueue::Buffer::const_iterator it = testRobotLaserQueue.
buffer().begin(); it != testRobotLaserQueue.
buffer().end(); ++it) {
214 VelocityMeasurement velocityMeasurement = OdomConvert::convertToVelocity(motionMeasurement);
218 calibratedVelocityMeasurment.
setVl(odomCalib(0) * calibratedVelocityMeasurment.
vl());
219 calibratedVelocityMeasurment.
setVr(odomCalib(1) * calibratedVelocityMeasurment.
vr());
220 MotionMeasurement mm = OdomConvert::convertToMotion(calibratedVelocityMeasurment, odomCalib(2));
225 SE2 calOdomPose = prevCalibratedPose * remappedOdom;
231 prevCalibratedPose = calOdomPose;
238 if (outputfilename.size() > 0) {
239 Gm2dlIO::updateLaserData(optimizer);
240 cerr <<
"Writing " << outputfilename <<
" ... ";
241 bool writeStatus = Gm2dlIO::writeGm2dl(outputfilename, optimizer);
242 cerr << (writeStatus ?
"done." :
"failed") << endl;
const SE2 & odomPose() const
int id() const
returns the id
const Vector3D & measurement() const
int main(int argc, char **argv)
const Buffer & buffer() const
Command line parsing of argc and argv.
HyperGraph::VertexSet & visited()
Vector3D toVector() const
convert to a 3D vector (x, y, theta)
laser measurement obtained by a robot
int optimize(int iterations, bool online=false)
void computeActiveErrors()
2D pose Vertex, (x,y,theta)
const VertexIDMap & vertices() const
Vertex * vertex(int id)
returns the vertex number id appropriately casted
utility functions for handling time related stuff
virtual Vertex * findGauge()
finds a gauge in the graph to remove the undefined dof.
double chi2() const
returns the chi2 of the current configuration
bool parseArgs(int argc, char **argv, bool exitOnError=true)
virtual bool save(std::ostream &os, int level=0) const
save the graph to a stream. Again uses the Factory system.
const Eigen::Rotation2Dd & rotation() const
rotational component
void shortestPaths(HyperGraph::Vertex *v, HyperDijkstra::CostFunction *cost, double maxDistance=std::numeric_limits< double >::max(), double comparisonConditioner=1e-3, bool directed=false, double maxEdgeCost=std::numeric_limits< double >::max())
void setVerbose(bool verbose)
const EdgeSet & edges() const
velocity measurement of a differential robot
void fromVector(const Vector3D &v)
assign from a 3D vector (x, y, theta)
void setForceStopFlag(bool *flag)
void paramLeftOver(const std::string &name, std::string &p, const std::string &defValue, const std::string &desc, bool optional=false)
A 2D odometry measurement expressed as a transformation.
void addOdometryCalibLinksDifferential(SparseOptimizer &optimizer, const DataQueue &odomData)
void param(const std::string &name, bool &p, bool defValue, const std::string &desc)
void sigquit_handler(int sig)
a simple queue to store data and retrieve based on a timestamp
A general case Vertex for optimization.
void allocateSolverForSclam(SparseOptimizer &optimizer, bool levenberg)
bool fixed() const
true => this node is fixed during the optimization
const EstimateType & estimate() const
return the current estimate of the vertex
SE2 inverse() const
invert :-)
void setFixed(bool fixed)
true => this node should be considered fixed during the optimization
virtual bool initializeOptimization(HyperGraph::EdgeSet &eset)
const Vector2D & translation() const
translational component