39 #include <gtsam/geometry/Pose2.h> 40 #include <gtsam/geometry/Pose3.h> 41 #include <gtsam/inference/Key.h> 42 #include <gtsam/inference/Symbol.h> 43 #include <gtsam/slam/PriorFactor.h> 44 #include <gtsam/slam/BetweenFactor.h> 45 #include <gtsam/nonlinear/NonlinearFactorGraph.h> 46 #include <gtsam/nonlinear/GaussNewtonOptimizer.h> 47 #include <gtsam/nonlinear/DoglegOptimizer.h> 48 #include <gtsam/nonlinear/LevenbergMarquardtOptimizer.h> 49 #include <gtsam/nonlinear/NonlinearOptimizer.h> 50 #include <gtsam/nonlinear/Marginals.h> 51 #include <gtsam/nonlinear/Values.h> 53 #ifdef RTABMAP_VERTIGO 59 #endif // end RTABMAP_GTSAM 80 const std::map<int, Transform> & poses,
81 const std::multimap<int, Link> & edgeConstraints,
82 cv::Mat & outputCovariance,
83 std::list<std::map<int, Transform> > * intermediateGraphes,
87 outputCovariance = cv::Mat::eye(6,6,CV_64FC1);
88 std::map<int, Transform> optimizedPoses;
91 #ifndef RTABMAP_VERTIGO 94 UWARN(
"Vertigo robust optimization is not available! Robust optimization is now disabled.");
99 UDEBUG(
"Optimizing graph...");
100 if(edgeConstraints.size()>=1 && poses.size()>=2 &&
iterations() > 0)
102 gtsam::NonlinearFactorGraph graph;
107 for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
109 if(iter->second.from() == iter->second.to())
121 const Transform & initialPose = poses.at(rootId);
124 gtsam::noiseModel::Diagonal::shared_ptr priorNoise = gtsam::noiseModel::Diagonal::Variances(gtsam::Vector3(0.01, 0.01, 0.01));
125 graph.add(gtsam::PriorFactor<gtsam::Pose2>(rootId, gtsam::Pose2(initialPose.
x(), initialPose.
y(), initialPose.
theta()), priorNoise));
129 gtsam::noiseModel::Diagonal::shared_ptr priorNoise = gtsam::noiseModel::Diagonal::Variances((gtsam::Vector(6) << 1
e-6, 1
e-6, 1
e-6, 1
e-4, 1
e-4, 1
e-4).finished());
130 graph.add(gtsam::PriorFactor<gtsam::Pose3>(rootId, gtsam::Pose3(initialPose.
toEigen4d()), priorNoise));
134 UDEBUG(
"fill poses to gtsam...");
135 gtsam::Values initialEstimate;
136 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
138 UASSERT(!iter->second.isNull());
141 initialEstimate.insert(iter->first, gtsam::Pose2(iter->second.x(), iter->second.y(), iter->second.theta()));
145 initialEstimate.insert(iter->first, gtsam::Pose3(iter->second.toEigen4d()));
149 UDEBUG(
"fill edges to gtsam...");
150 int switchCounter = poses.rbegin()->first+1;
151 for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
153 int id1 = iter->second.from();
154 int id2 = iter->second.to();
155 UASSERT(!iter->second.transform().isNull());
162 Eigen::Matrix<double, 3, 3> information = Eigen::Matrix<double, 3, 3>::Identity();
165 information(0,0) = iter->second.infMatrix().at<
double>(0,0);
166 information(0,1) = iter->second.infMatrix().at<
double>(0,1);
167 information(0,2) = iter->second.infMatrix().at<
double>(0,5);
168 information(1,0) = iter->second.infMatrix().at<
double>(1,0);
169 information(1,1) = iter->second.infMatrix().at<
double>(1,1);
170 information(1,2) = iter->second.infMatrix().at<
double>(1,5);
171 information(2,0) = iter->second.infMatrix().at<
double>(5,0);
172 information(2,1) = iter->second.infMatrix().at<
double>(5,1);
173 information(2,2) = iter->second.infMatrix().at<
double>(5,5);
176 gtsam::noiseModel::Gaussian::shared_ptr model = gtsam::noiseModel::Gaussian::Information(information);
177 graph.add(gtsam::PriorFactor<gtsam::Pose2>(id1, gtsam::Pose2(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().theta()), model));
181 Eigen::Matrix<double, 6, 6> information = Eigen::Matrix<double, 6, 6>::Identity();
184 memcpy(information.data(), iter->second.infMatrix().data, iter->second.infMatrix().total()*
sizeof(double));
187 Eigen::Matrix<double, 6, 6> mgtsam = Eigen::Matrix<double, 6, 6>::Identity();
188 mgtsam.block(0,0,3,3) = information.block(3,3,3,3);
189 mgtsam.block(3,3,3,3) = information.block(0,0,3,3);
190 mgtsam.block(0,3,3,3) = information.block(0,3,3,3);
191 mgtsam.block(3,0,3,3) = information.block(3,0,3,3);
192 gtsam::SharedNoiseModel model = gtsam::noiseModel::Gaussian::Information(mgtsam);
194 graph.add(gtsam::PriorFactor<gtsam::Pose3>(id1, gtsam::Pose3(iter->second.transform().toEigen4d()), model));
200 #ifdef RTABMAP_VERTIGO 219 gtsam::noiseModel::Diagonal::shared_ptr switchPriorModel = gtsam::noiseModel::Diagonal::Sigmas(gtsam::Vector1(1.0));
220 graph.add(gtsam::PriorFactor<vertigo::SwitchVariableLinear> (gtsam::Symbol(
's',switchCounter),
vertigo::SwitchVariableLinear(prior), switchPriorModel));
226 Eigen::Matrix<double, 3, 3> information = Eigen::Matrix<double, 3, 3>::Identity();
229 information(0,0) = iter->second.infMatrix().at<
double>(0,0);
230 information(0,1) = iter->second.infMatrix().at<
double>(0,1);
231 information(0,2) = iter->second.infMatrix().at<
double>(0,5);
232 information(1,0) = iter->second.infMatrix().at<
double>(1,0);
233 information(1,1) = iter->second.infMatrix().at<
double>(1,1);
234 information(1,2) = iter->second.infMatrix().at<
double>(1,5);
235 information(2,0) = iter->second.infMatrix().at<
double>(5,0);
236 information(2,1) = iter->second.infMatrix().at<
double>(5,1);
237 information(2,2) = iter->second.infMatrix().at<
double>(5,5);
239 gtsam::noiseModel::Gaussian::shared_ptr model = gtsam::noiseModel::Gaussian::Information(information);
241 #ifdef RTABMAP_VERTIGO 252 graph.add(gtsam::BetweenFactor<gtsam::Pose2>(id1, id2, gtsam::Pose2(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().theta()), model));
257 Eigen::Matrix<double, 6, 6> information = Eigen::Matrix<double, 6, 6>::Identity();
260 memcpy(information.data(), iter->second.infMatrix().data, iter->second.infMatrix().total()*
sizeof(double));
263 Eigen::Matrix<double, 6, 6> mgtsam = Eigen::Matrix<double, 6, 6>::Identity();
264 mgtsam.block(0,0,3,3) = information.block(3,3,3,3);
265 mgtsam.block(3,3,3,3) = information.block(0,0,3,3);
266 mgtsam.block(0,3,3,3) = information.block(0,3,3,3);
267 mgtsam.block(3,0,3,3) = information.block(3,0,3,3);
268 gtsam::SharedNoiseModel model = gtsam::noiseModel::Gaussian::Information(mgtsam);
270 #ifdef RTABMAP_VERTIGO 282 graph.add(gtsam::BetweenFactor<gtsam::Pose3>(id1, id2, gtsam::Pose3(iter->second.transform().toEigen4d()), model));
288 UDEBUG(
"create optimizer");
289 gtsam::NonlinearOptimizer * optimizer;
293 gtsam::DoglegParams parameters;
294 parameters.relativeErrorTol =
epsilon();
296 optimizer =
new gtsam::DoglegOptimizer(graph, initialEstimate, parameters);
300 gtsam::GaussNewtonParams parameters;
301 parameters.relativeErrorTol =
epsilon();
303 optimizer =
new gtsam::GaussNewtonOptimizer(graph, initialEstimate, parameters);
307 gtsam::LevenbergMarquardtParams parameters;
308 parameters.relativeErrorTol =
epsilon();
310 optimizer =
new gtsam::LevenbergMarquardtOptimizer(graph, initialEstimate, parameters);
316 double lastError = optimizer->error();
319 if(intermediateGraphes && i > 0)
321 std::map<int, Transform> tmpPoses;
322 for(gtsam::Values::const_iterator iter=optimizer->values().begin(); iter!=optimizer->values().end(); ++iter)
324 if(iter->value.dim() > 1)
328 gtsam::Pose2 p = iter->value.cast<gtsam::Pose2>();
329 tmpPoses.insert(std::make_pair((
int)iter->key,
Transform(p.x(), p.y(), p.theta())));
333 gtsam::Pose3 p = iter->value.cast<gtsam::Pose3>();
338 intermediateGraphes->push_back(tmpPoses);
342 optimizer->iterate();
345 catch(gtsam::IndeterminantLinearSystemException &
e)
347 UERROR(
"GTSAM exception caught: %s", e.what());
349 return optimizedPoses;
353 double error = optimizer->error();
354 UDEBUG(
"iteration %d error =%f", i+1, error);
355 double errorDelta = lastError - error;
356 if(i>0 && errorDelta < this->
epsilon())
360 UDEBUG(
"Negative improvement?! Ignore and continue optimizing... (%f < %f)", errorDelta, this->
epsilon());
364 UINFO(
"Stop optimizing, not enough improvement (%f < %f)", errorDelta, this->
epsilon());
368 else if(i==0 && error < this->
epsilon())
370 UINFO(
"Stop optimizing, error is already under epsilon (%f < %f)", error, this->
epsilon());
377 *finalError = lastError;
381 *iterationsDone = it;
383 UINFO(
"GTSAM optimizing end (%d iterations done, error=%f (initial=%f final=%f), time=%f s)",
384 optimizer->iterations(), optimizer->error(), graph.error(initialEstimate), graph.error(optimizer->values()), timer.
ticks());
386 gtsam::Marginals marginals(graph, optimizer->values());
387 for(gtsam::Values::const_iterator iter=optimizer->values().begin(); iter!=optimizer->values().end(); ++iter)
389 if(iter->value.dim() > 1)
393 gtsam::Pose2 p = iter->value.cast<gtsam::Pose2>();
394 optimizedPoses.insert(std::make_pair((
int)iter->key,
Transform(p.x(), p.y(), p.theta())));
398 gtsam::Pose3 p = iter->value.cast<gtsam::Pose3>();
407 gtsam::Marginals marginals(graph, optimizer->values());
408 gtsam::Matrix info = marginals.marginalCovariance(optimizer->values().rbegin()->key);
409 UINFO(
"Computed marginals = %fs (key=%d)", t.
ticks(), optimizer->values().rbegin()->key);
412 UASSERT(info.cols() == 3 && info.cols() == 3);
413 outputCovariance.at<
double>(0,0) = info(0,0);
414 outputCovariance.at<
double>(0,1) = info(0,1);
415 outputCovariance.at<
double>(0,5) = info(0,2);
416 outputCovariance.at<
double>(1,0) = info(1,0);
417 outputCovariance.at<
double>(1,1) = info(1,1);
418 outputCovariance.at<
double>(1,5) = info(1,2);
419 outputCovariance.at<
double>(5,0) = info(2,0);
420 outputCovariance.at<
double>(5,1) = info(2,1);
421 outputCovariance.at<
double>(5,5) = info(2,2);
425 UASSERT(info.cols() == 6 && info.cols() == 6);
426 Eigen::Matrix<double, 6, 6> mgtsam = Eigen::Matrix<double, 6, 6>::Identity();
427 mgtsam.block(3,3,3,3) = info.block(0,0,3,3);
428 mgtsam.block(0,0,3,3) = info.block(3,3,3,3);
429 mgtsam.block(0,3,3,3) = info.block(0,3,3,3);
430 mgtsam.block(3,0,3,3) = info.block(3,0,3,3);
431 memcpy(outputCovariance.data, mgtsam.data(), outputCovariance.total()*
sizeof(double));
433 }
catch(std::exception&
e) {
434 cout << e.what() << endl;
439 else if(poses.size() == 1 ||
iterations() <= 0)
441 optimizedPoses = poses;
445 UWARN(
"This method should be called at least with 1 pose!");
447 UDEBUG(
"Optimizing graph...end!");
449 UERROR(
"Not built with GTSAM support!");
451 return optimizedPoses;
bool priorsIgnored() const
static bool parse(const ParametersMap ¶meters, const std::string &key, bool &value)
virtual void parseParameters(const ParametersMap ¶meters)
GLM_FUNC_DECL genType e()
std::map< std::string, std::string > ParametersMap
bool isCovarianceIgnored() const
Basic mathematics functions.
Some conversion functions.
#define UASSERT(condition)
Wrappers of STL for convenient functions.
virtual void parseParameters(const ParametersMap ¶meters)
bool uContains(const std::list< V > &list, const V &value)
void setRobust(bool enabled)
ULogger class and convenient macros.
virtual std::map< int, Transform > optimize(int rootId, const std::map< int, Transform > &poses, const std::multimap< int, Link > &edgeConstraints, cv::Mat &outputCovariance, std::list< std::map< int, Transform > > *intermediateGraphes=0, double *finalError=0, int *iterationsDone=0)