| 
									
										
										
										
											2018-12-15 04:12:33 +08:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * @file ISAM2_SmartFactorStereo_IMU.cpp | 
					
						
							|  |  |  |  * @brief test of iSAM2 with smart stereo factors and IMU preintegration, | 
					
						
							|  |  |  |  * originally used to debug valgrind invalid reads with Eigen | 
					
						
							|  |  |  |  * @author Nghia Ho | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Setup is a stationary stereo camera with an IMU attached. | 
					
						
							|  |  |  |  * The data file is at examples/Data/ISAM2_SmartFactorStereo_IMU.txt | 
					
						
							|  |  |  |  * It contains 5 frames of stereo matches and IMU data. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #include <gtsam/navigation/CombinedImuFactor.h>
 | 
					
						
							|  |  |  | #include <gtsam/nonlinear/ISAM2.h>
 | 
					
						
							|  |  |  | #include <gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <fstream>
 | 
					
						
							|  |  |  | #include <iostream>
 | 
					
						
							|  |  |  | #include <sstream>
 | 
					
						
							| 
									
										
										
										
											2019-01-01 01:30:53 +08:00
										 |  |  | #include <string>
 | 
					
						
							| 
									
										
										
										
											2018-12-15 04:12:33 +08:00
										 |  |  | #include <vector>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace std; | 
					
						
							|  |  |  | using namespace gtsam; | 
					
						
							|  |  |  | using symbol_shorthand::X; | 
					
						
							|  |  |  | using symbol_shorthand::V; | 
					
						
							|  |  |  | using symbol_shorthand::B; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct IMUHelper { | 
					
						
							|  |  |  |   IMUHelper() { | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       auto gaussian = noiseModel::Diagonal::Sigmas( | 
					
						
							|  |  |  |           (Vector(6) << Vector3::Constant(5.0e-2), Vector3::Constant(5.0e-3)) | 
					
						
							|  |  |  |               .finished()); | 
					
						
							|  |  |  |       auto huber = noiseModel::Robust::Create( | 
					
						
							|  |  |  |           noiseModel::mEstimator::Huber::Create(1.345), gaussian); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       biasNoiseModel = huber; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       auto gaussian = noiseModel::Isotropic::Sigma(3, 0.01); | 
					
						
							|  |  |  |       auto huber = noiseModel::Robust::Create( | 
					
						
							|  |  |  |           noiseModel::mEstimator::Huber::Create(1.345), gaussian); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       velocityNoiseModel = huber; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // expect IMU to be rotated in image space co-ords
 | 
					
						
							| 
									
										
										
										
											2023-01-18 06:05:12 +08:00
										 |  |  |     auto p = std::make_shared<PreintegratedCombinedMeasurements::Params>( | 
					
						
							| 
									
										
										
										
											2018-12-15 04:12:33 +08:00
										 |  |  |         Vector3(0.0, 9.8, 0.0)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     p->accelerometerCovariance = | 
					
						
							|  |  |  |         I_3x3 * pow(0.0565, 2.0);  // acc white noise in continuous
 | 
					
						
							|  |  |  |     p->integrationCovariance = | 
					
						
							|  |  |  |         I_3x3 * 1e-9;  // integration uncertainty continuous
 | 
					
						
							|  |  |  |     p->gyroscopeCovariance = | 
					
						
							|  |  |  |         I_3x3 * pow(4.0e-5, 2.0);  // gyro white noise in continuous
 | 
					
						
							|  |  |  |     p->biasAccCovariance = I_3x3 * pow(0.00002, 2.0);  // acc bias in continuous
 | 
					
						
							|  |  |  |     p->biasOmegaCovariance = | 
					
						
							|  |  |  |         I_3x3 * pow(0.001, 2.0);  // gyro bias in continuous
 | 
					
						
							|  |  |  |     p->biasAccOmegaInt = Matrix::Identity(6, 6) * 1e-5; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // body to IMU rotation
 | 
					
						
							| 
									
										
										
										
											2018-12-15 04:18:43 +08:00
										 |  |  |     Rot3 iRb(0.036129, -0.998727, 0.035207, | 
					
						
							|  |  |  |              0.045417, -0.033553, -0.998404, | 
					
						
							|  |  |  |              0.998315, 0.037670, 0.044147); | 
					
						
							| 
									
										
										
										
											2018-12-15 04:12:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // body to IMU translation (meters)
 | 
					
						
							|  |  |  |     Point3 iTb(0.03, -0.025, -0.06); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // body in this example is the left camera
 | 
					
						
							|  |  |  |     p->body_P_sensor = Pose3(iRb, iTb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Rot3 prior_rotation = Rot3(I_3x3); | 
					
						
							|  |  |  |     Pose3 prior_pose(prior_rotation, Point3(0, 0, 0)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Vector3 acc_bias(0.0, -0.0942015, 0.0);  // in camera frame
 | 
					
						
							|  |  |  |     Vector3 gyro_bias(-0.00527483, -0.00757152, -0.00469968); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     priorImuBias = imuBias::ConstantBias(acc_bias, gyro_bias); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     prevState = NavState(prior_pose, Vector3(0, 0, 0)); | 
					
						
							|  |  |  |     propState = prevState; | 
					
						
							|  |  |  |     prevBias = priorImuBias; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     preintegrated = new PreintegratedCombinedMeasurements(p, priorImuBias); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   imuBias::ConstantBias priorImuBias;  // assume zero initial bias
 | 
					
						
							|  |  |  |   noiseModel::Robust::shared_ptr velocityNoiseModel; | 
					
						
							|  |  |  |   noiseModel::Robust::shared_ptr biasNoiseModel; | 
					
						
							|  |  |  |   NavState prevState; | 
					
						
							|  |  |  |   NavState propState; | 
					
						
							|  |  |  |   imuBias::ConstantBias prevBias; | 
					
						
							|  |  |  |   PreintegratedCombinedMeasurements* preintegrated; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int main(int argc, char* argv[]) { | 
					
						
							|  |  |  |   if (argc != 2) { | 
					
						
							| 
									
										
										
										
											2018-12-15 04:16:19 +08:00
										 |  |  |     cout << "./ISAM2_SmartFactorStereo_IMU [data.txt]\n"; | 
					
						
							| 
									
										
										
										
											2018-12-15 04:12:33 +08:00
										 |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ifstream in(argv[1]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!in) { | 
					
						
							|  |  |  |     cerr << "error opening: " << argv[1] << "\n"; | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Camera parameters
 | 
					
						
							|  |  |  |   double fx = 822.37; | 
					
						
							|  |  |  |   double fy = 822.37; | 
					
						
							|  |  |  |   double cx = 538.73; | 
					
						
							|  |  |  |   double cy = 579.10; | 
					
						
							| 
									
										
										
										
											2018-12-15 04:18:43 +08:00
										 |  |  |   double baseline = 0.372;  // meters
 | 
					
						
							| 
									
										
										
										
											2018-12-15 04:12:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Cal3_S2Stereo::shared_ptr K(new Cal3_S2Stereo(fx, fy, 0.0, cx, cy, baseline)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ISAM2Params parameters; | 
					
						
							|  |  |  |   parameters.relinearizeThreshold = 0.1; | 
					
						
							|  |  |  |   ISAM2 isam(parameters); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Create a factor graph
 | 
					
						
							|  |  |  |   std::map<size_t, SmartStereoProjectionPoseFactor::shared_ptr> smartFactors; | 
					
						
							|  |  |  |   NonlinearFactorGraph graph; | 
					
						
							|  |  |  |   Values initialEstimate; | 
					
						
							|  |  |  |   IMUHelper imu; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Pose prior - at identity
 | 
					
						
							|  |  |  |   auto priorPoseNoise = noiseModel::Diagonal::Sigmas( | 
					
						
							|  |  |  |       (Vector(6) << Vector3::Constant(0.1), Vector3::Constant(0.1)).finished()); | 
					
						
							| 
									
										
										
										
											2022-07-08 00:31:27 +08:00
										 |  |  |   graph.addPrior(X(1), Pose3::Identity(), priorPoseNoise); | 
					
						
							|  |  |  |   initialEstimate.insert(X(0), Pose3::Identity()); | 
					
						
							| 
									
										
										
										
											2018-12-15 04:12:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Bias prior
 | 
					
						
							| 
									
										
										
										
											2020-04-13 01:10:09 +08:00
										 |  |  |   graph.addPrior(B(1), imu.priorImuBias, | 
					
						
							| 
									
										
										
										
											2020-04-12 08:09:54 +08:00
										 |  |  |                                                imu.biasNoiseModel); | 
					
						
							| 
									
										
										
										
											2018-12-15 04:12:33 +08:00
										 |  |  |   initialEstimate.insert(B(0), imu.priorImuBias); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Velocity prior - assume stationary
 | 
					
						
							| 
									
										
										
										
											2020-04-13 01:10:09 +08:00
										 |  |  |   graph.addPrior(V(1), Vector3(0, 0, 0), imu.velocityNoiseModel); | 
					
						
							| 
									
										
										
										
											2018-12-15 04:12:33 +08:00
										 |  |  |   initialEstimate.insert(V(0), Vector3(0, 0, 0)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int lastFrame = 1; | 
					
						
							|  |  |  |   int frame; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while (true) { | 
					
						
							|  |  |  |     char line[1024]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     in.getline(line, sizeof(line)); | 
					
						
							|  |  |  |     stringstream ss(line); | 
					
						
							|  |  |  |     char type; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ss >> type; | 
					
						
							|  |  |  |     ss >> frame; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (frame != lastFrame || in.eof()) { | 
					
						
							|  |  |  |       cout << "Running iSAM for frame: " << lastFrame << "\n"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-08 00:31:27 +08:00
										 |  |  |       initialEstimate.insert(X(lastFrame), Pose3::Identity()); | 
					
						
							| 
									
										
										
										
											2018-12-15 04:12:33 +08:00
										 |  |  |       initialEstimate.insert(V(lastFrame), Vector3(0, 0, 0)); | 
					
						
							|  |  |  |       initialEstimate.insert(B(lastFrame), imu.prevBias); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       CombinedImuFactor imuFactor(X(lastFrame - 1), V(lastFrame - 1), | 
					
						
							|  |  |  |                                   X(lastFrame), V(lastFrame), B(lastFrame - 1), | 
					
						
							|  |  |  |                                   B(lastFrame), *imu.preintegrated); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       graph.add(imuFactor); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       isam.update(graph, initialEstimate); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       Values currentEstimate = isam.calculateEstimate(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       imu.propState = imu.preintegrated->predict(imu.prevState, imu.prevBias); | 
					
						
							|  |  |  |       imu.prevState = NavState(currentEstimate.at<Pose3>(X(lastFrame)), | 
					
						
							|  |  |  |                                currentEstimate.at<Vector3>(V(lastFrame))); | 
					
						
							|  |  |  |       imu.prevBias = currentEstimate.at<imuBias::ConstantBias>(B(lastFrame)); | 
					
						
							|  |  |  |       imu.preintegrated->resetIntegrationAndSetBias(imu.prevBias); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       graph.resize(0); | 
					
						
							|  |  |  |       initialEstimate.clear(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (in.eof()) { | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (type == 'i') {  // Process IMU measurement
 | 
					
						
							|  |  |  |       double ax, ay, az; | 
					
						
							|  |  |  |       double gx, gy, gz; | 
					
						
							|  |  |  |       double dt = 1 / 800.0;  // IMU at ~800Hz
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       ss >> ax; | 
					
						
							|  |  |  |       ss >> ay; | 
					
						
							|  |  |  |       ss >> az; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       ss >> gx; | 
					
						
							|  |  |  |       ss >> gy; | 
					
						
							|  |  |  |       ss >> gz; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       Vector3 acc(ax, ay, az); | 
					
						
							|  |  |  |       Vector3 gyr(gx, gy, gz); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       imu.preintegrated->integrateMeasurement(acc, gyr, dt); | 
					
						
							|  |  |  |     } else if (type == 's') {  // Process stereo measurement
 | 
					
						
							|  |  |  |       int landmark; | 
					
						
							|  |  |  |       double xl, xr, y; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       ss >> landmark; | 
					
						
							|  |  |  |       ss >> xl; | 
					
						
							|  |  |  |       ss >> xr; | 
					
						
							|  |  |  |       ss >> y; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (smartFactors.count(landmark) == 0) { | 
					
						
							|  |  |  |         auto gaussian = noiseModel::Isotropic::Sigma(3, 1.0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         SmartProjectionParams params(HESSIAN, ZERO_ON_DEGENERACY); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         smartFactors[landmark] = SmartStereoProjectionPoseFactor::shared_ptr( | 
					
						
							|  |  |  |             new SmartStereoProjectionPoseFactor(gaussian, params)); | 
					
						
							|  |  |  |         graph.push_back(smartFactors[landmark]); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       smartFactors[landmark]->add(StereoPoint2(xl, xr, y), X(frame), K); | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2019-01-01 01:30:53 +08:00
										 |  |  |       throw runtime_error("unexpected data type: " + string(1, type)); | 
					
						
							| 
									
										
										
										
											2018-12-15 04:12:33 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     lastFrame = frame; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 0; | 
					
						
							|  |  |  | } |