ImuFactorsExample.cpp
Go to the documentation of this file.
1 /* ----------------------------------------------------------------------------
2 
3  * GTSAM Copyright 2010, Georgia Tech Research Corporation,
4  * Atlanta, Georgia 30332-0415
5  * All Rights Reserved
6  * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
7 
8  * See LICENSE for the license information
9 
10  * -------------------------------------------------------------------------- */
11 
38 #include <boost/program_options.hpp>
39 
40 // GTSAM related includes.
41 #include <gtsam/inference/Symbol.h>
45 #include <gtsam/nonlinear/ISAM2.h>
49 #include <gtsam/slam/dataset.h>
50 
51 #include <cstring>
52 #include <cassert>
53 #include <fstream>
54 #include <iostream>
55 
56 using namespace gtsam;
57 using namespace std;
58 
59 using symbol_shorthand::B; // Bias (ax,ay,az,gx,gy,gz)
60 using symbol_shorthand::V; // Vel (xdot,ydot,zdot)
61 using symbol_shorthand::X; // Pose3 (x,y,z,r,p,y)
62 
63 namespace po = boost::program_options;
64 
65 po::variables_map parseOptions(int argc, char* argv[]) {
66  po::options_description desc;
67  desc.add_options()("help,h", "produce help message")(
68  "data_csv_path", po::value<string>()->default_value("imuAndGPSdata.csv"),
69  "path to the CSV file with the IMU data")(
70  "output_filename",
71  po::value<string>()->default_value("imuFactorExampleResults.csv"),
72  "path to the result file to use")("use_isam", po::bool_switch(),
73  "use ISAM as the optimizer");
74 
75  po::variables_map vm;
76  po::store(po::parse_command_line(argc, argv, desc), vm);
77 
78  if (vm.count("help")) {
79  cout << desc << "\n";
80  exit(1);
81  }
82 
83  return vm;
84 }
85 
86 std::shared_ptr<PreintegratedCombinedMeasurements::Params> imuParams() {
87  // We use the sensor specs to build the noise model for the IMU factor.
88  double accel_noise_sigma = 0.0003924;
89  double gyro_noise_sigma = 0.000205689024915;
90  double accel_bias_rw_sigma = 0.004905;
91  double gyro_bias_rw_sigma = 0.000001454441043;
92  Matrix33 measured_acc_cov = I_3x3 * pow(accel_noise_sigma, 2);
93  Matrix33 measured_omega_cov = I_3x3 * pow(gyro_noise_sigma, 2);
94  Matrix33 integration_error_cov =
95  I_3x3 * 1e-8; // error committed in integrating position from velocities
96  Matrix33 bias_acc_cov = I_3x3 * pow(accel_bias_rw_sigma, 2);
97  Matrix33 bias_omega_cov = I_3x3 * pow(gyro_bias_rw_sigma, 2);
98  Matrix66 bias_acc_omega_init =
99  I_6x6 * 1e-5; // error in the bias used for preintegration
100 
102  // PreintegrationBase params:
103  p->accelerometerCovariance =
104  measured_acc_cov; // acc white noise in continuous
105  p->integrationCovariance =
106  integration_error_cov; // integration uncertainty continuous
107  // should be using 2nd order integration
108  // PreintegratedRotation params:
109  p->gyroscopeCovariance =
110  measured_omega_cov; // gyro white noise in continuous
111  // PreintegrationCombinedMeasurements params:
112  p->biasAccCovariance = bias_acc_cov; // acc bias in continuous
113  p->biasOmegaCovariance = bias_omega_cov; // gyro bias in continuous
114  p->biasAccOmegaInt = bias_acc_omega_init;
115 
116  return p;
117 }
118 
119 int main(int argc, char* argv[]) {
120  string data_filename, output_filename;
121 
122  bool use_isam = false;
123 
124  po::variables_map var_map = parseOptions(argc, argv);
125 
126  data_filename = findExampleDataFile(var_map["data_csv_path"].as<string>());
127  output_filename = var_map["output_filename"].as<string>();
128  use_isam = var_map["use_isam"].as<bool>();
129 
130  ISAM2* isam2 = 0;
131  if (use_isam) {
132  printf("Using ISAM2\n");
134  parameters.relinearizeThreshold = 0.01;
135  parameters.relinearizeSkip = 1;
136  isam2 = new ISAM2(parameters);
137 
138  } else {
139  printf("Using Levenberg Marquardt Optimizer\n");
140  }
141 
142  // Set up output file for plotting errors
143  FILE* fp_out = fopen(output_filename.c_str(), "w+");
144  fprintf(fp_out,
145  "#time(s),x(m),y(m),z(m),qx,qy,qz,qw,gt_x(m),gt_y(m),gt_z(m),gt_qx,"
146  "gt_qy,gt_qz,gt_qw\n");
147 
148  // Begin parsing the CSV file. Input the first line for initialization.
149  // From there, we'll iterate through the file and we'll preintegrate the IMU
150  // or add in the GPS given the input.
151  ifstream file(data_filename.c_str());
152  string value;
153 
154  // Format is (N,E,D,qX,qY,qZ,qW,velN,velE,velD)
155  Vector10 initial_state;
156  getline(file, value, ','); // i
157  for (int i = 0; i < 9; i++) {
158  getline(file, value, ',');
159  initial_state(i) = stof(value.c_str());
160  }
161  getline(file, value, '\n');
162  initial_state(9) = stof(value.c_str());
163  cout << "initial state:\n" << initial_state.transpose() << "\n\n";
164 
165  // Assemble initial quaternion through GTSAM constructor
166  // ::quaternion(w,x,y,z);
167  Rot3 prior_rotation = Rot3::Quaternion(initial_state(6), initial_state(3),
168  initial_state(4), initial_state(5));
169  Point3 prior_point(initial_state.head<3>());
170  Pose3 prior_pose(prior_rotation, prior_point);
171  Vector3 prior_velocity(initial_state.tail<3>());
172  imuBias::ConstantBias prior_imu_bias; // assume zero initial bias
173 
174  Values initial_values;
175  int correction_count = 0;
176  initial_values.insert(X(correction_count), prior_pose);
177  initial_values.insert(V(correction_count), prior_velocity);
178  initial_values.insert(B(correction_count), prior_imu_bias);
179 
180  // Assemble prior noise model and add it the graph.`
181  auto pose_noise_model = noiseModel::Diagonal::Sigmas(
182  (Vector(6) << 0.01, 0.01, 0.01, 0.5, 0.5, 0.5)
183  .finished()); // rad,rad,rad,m, m, m
184  auto velocity_noise_model = noiseModel::Isotropic::Sigma(3, 0.1); // m/s
185  auto bias_noise_model = noiseModel::Isotropic::Sigma(6, 1e-3);
186 
187  // Add all prior factors (pose, velocity, bias) to the graph.
189  graph->addPrior(X(correction_count), prior_pose, pose_noise_model);
190  graph->addPrior(V(correction_count), prior_velocity, velocity_noise_model);
191  graph->addPrior(B(correction_count), prior_imu_bias, bias_noise_model);
192 
193  auto p = imuParams();
194 
195  std::shared_ptr<PreintegrationType> preintegrated =
196  std::make_shared<PreintegratedImuMeasurements>(p, prior_imu_bias);
197 
198  assert(preintegrated);
199 
200  // Store previous state for imu integration and latest predicted outcome.
201  NavState prev_state(prior_pose, prior_velocity);
202  NavState prop_state = prev_state;
203  imuBias::ConstantBias prev_bias = prior_imu_bias;
204 
205  // Keep track of total error over the entire run as simple performance metric.
206  double current_position_error = 0.0, current_orientation_error = 0.0;
207 
208  double output_time = 0.0;
209  double dt = 0.005; // The real system has noise, but here, results are nearly
210  // exactly the same, so keeping this for simplicity.
211 
212  // All priors have been set up, now iterate through the data file.
213  while (file.good()) {
214  // Parse out first value
215  getline(file, value, ',');
216  int type = stoi(value.c_str());
217 
218  if (type == 0) { // IMU measurement
219  Vector6 imu;
220  for (int i = 0; i < 5; ++i) {
221  getline(file, value, ',');
222  imu(i) = stof(value.c_str());
223  }
224  getline(file, value, '\n');
225  imu(5) = stof(value.c_str());
226 
227  // Adding the IMU preintegration.
228  preintegrated->integrateMeasurement(imu.head<3>(), imu.tail<3>(), dt);
229 
230  } else if (type == 1) { // GPS measurement
231  Vector7 gps;
232  for (int i = 0; i < 6; ++i) {
233  getline(file, value, ',');
234  gps(i) = stof(value.c_str());
235  }
236  getline(file, value, '\n');
237  gps(6) = stof(value.c_str());
238 
239  correction_count++;
240 
241  // Adding IMU factor and GPS factor and optimizing.
242  auto preint_imu =
243  dynamic_cast<const PreintegratedImuMeasurements&>(*preintegrated);
244  ImuFactor imu_factor(X(correction_count - 1), V(correction_count - 1),
245  X(correction_count), V(correction_count),
246  B(correction_count - 1), preint_imu);
247  graph->add(imu_factor);
248  imuBias::ConstantBias zero_bias(Vector3(0, 0, 0), Vector3(0, 0, 0));
250  B(correction_count - 1), B(correction_count), zero_bias,
251  bias_noise_model));
252 
253  auto correction_noise = noiseModel::Isotropic::Sigma(3, 1.0);
254  GPSFactor gps_factor(X(correction_count),
255  Point3(gps(0), // N,
256  gps(1), // E,
257  gps(2)), // D,
258  correction_noise);
259  graph->add(gps_factor);
260 
261  // Now optimize and compare results.
262  prop_state = preintegrated->predict(prev_state, prev_bias);
263  initial_values.insert(X(correction_count), prop_state.pose());
264  initial_values.insert(V(correction_count), prop_state.v());
265  initial_values.insert(B(correction_count), prev_bias);
266 
267  Values result;
268 
269  if (use_isam) {
270  isam2->update(*graph, initial_values);
271  result = isam2->calculateEstimate();
272 
273  // reset the graph
274  graph->resize(0);
275  initial_values.clear();
276 
277  } else {
278  LevenbergMarquardtOptimizer optimizer(*graph, initial_values);
279  result = optimizer.optimize();
280  }
281 
282  // Overwrite the beginning of the preintegration for the next step.
283  prev_state = NavState(result.at<Pose3>(X(correction_count)),
284  result.at<Vector3>(V(correction_count)));
285  prev_bias = result.at<imuBias::ConstantBias>(B(correction_count));
286 
287  // Reset the preintegration object.
288  preintegrated->resetIntegrationAndSetBias(prev_bias);
289 
290  // Print out the position and orientation error for comparison.
291  Vector3 gtsam_position = prev_state.pose().translation();
292  Vector3 position_error = gtsam_position - gps.head<3>();
293  current_position_error = position_error.norm();
294 
295  Quaternion gtsam_quat = prev_state.pose().rotation().toQuaternion();
296  Quaternion gps_quat(gps(6), gps(3), gps(4), gps(5));
297  Quaternion quat_error = gtsam_quat * gps_quat.inverse();
298  quat_error.normalize();
299  Vector3 euler_angle_error(quat_error.x() * 2, quat_error.y() * 2,
300  quat_error.z() * 2);
301  current_orientation_error = euler_angle_error.norm();
302 
303  // display statistics
304  cout << "Position error:" << current_position_error << "\t "
305  << "Angular error:" << current_orientation_error << "\n";
306 
307  fprintf(fp_out, "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f\n",
308  output_time, gtsam_position(0), gtsam_position(1),
309  gtsam_position(2), gtsam_quat.x(), gtsam_quat.y(), gtsam_quat.z(),
310  gtsam_quat.w(), gps(0), gps(1), gps(2), gps_quat.x(),
311  gps_quat.y(), gps_quat.z(), gps_quat.w());
312 
313  output_time += 1.0;
314 
315  } else {
316  cerr << "ERROR parsing file\n";
317  return 1;
318  }
319  }
320  fclose(fp_out);
321  cout << "Complete, results written to " << output_filename << "\n\n";
322 
323  return 0;
324 }
gtsam::ISAM2Params
Definition: ISAM2Params.h:136
gtsam::NonlinearOptimizer::optimize
virtual const Values & optimize()
Definition: NonlinearOptimizer.h:98
gtsam::ISAM2
Definition: ISAM2.h:45
gtsam.examples.DogLegOptimizerExample.type
type
Definition: DogLegOptimizerExample.py:111
e
Array< double, 1, 3 > e(1./3., 0.5, 2.)
gtsam::Rot3::Quaternion
static Rot3 Quaternion(double w, double x, double y, double z)
Definition: Rot3.h:208
LevenbergMarquardtOptimizer.h
A nonlinear optimizer that uses the Levenberg-Marquardt trust-region scheme.
dt
const double dt
Definition: testVelocityConstraint.cpp:15
main
int main(int argc, char *argv[])
Definition: ImuFactorsExample.cpp:119
E1::B
@ B
gtsam::NavState
Definition: NavState.h:38
gtsam::noiseModel::Diagonal::Sigmas
static shared_ptr Sigmas(const Vector &sigmas, bool smart=true)
Definition: NoiseModel.cpp:292
X
#define X
Definition: icosphere.cpp:20
gtsam::Vector3
Eigen::Vector3d Vector3
Definition: Vector.h:44
gtsam::NavState::v
const Vector3 & v() const
Return velocity as Vector3. Computation-free.
Definition: NavState.h:111
gtsam::Values::update
void update(Key j, const Value &val)
Definition: Values.cpp:170
gtsam::Vector
Eigen::VectorXd Vector
Definition: Vector.h:39
result
Values result
Definition: OdometryOptimize.cpp:8
make_changelog.desc
desc
Definition: make_changelog.py:71
gtsam::symbol_shorthand::X
Key X(std::uint64_t j)
Definition: inference/Symbol.h:171
gtsam::Values::at
const ValueType at(Key j) const
Definition: Values-inl.h:261
gtsam::FactorGraph::resize
virtual void resize(size_t size)
Definition: FactorGraph.h:367
dataset.h
utility functions for loading datasets
gtsam::PreintegrationCombinedParams::MakeSharedD
static std::shared_ptr< PreintegrationCombinedParams > MakeSharedD(double g=9.81)
Definition: PreintegrationCombinedParams.h:60
BetweenFactor.h
parseOptions
po::variables_map parseOptions(int argc, char *argv[])
Definition: ImuFactorsExample.cpp:65
gtsam::Rot3
Rot3 is a 3D rotation represented as a rotation matrix if the preprocessor symbol GTSAM_USE_QUATERNIO...
Definition: Rot3.h:58
gtsam::Pose3
Definition: Pose3.h:37
parameters
static ConjugateGradientParameters parameters
Definition: testIterative.cpp:33
gtsam::PreintegratedImuMeasurements
Definition: ImuFactor.h:68
gtsam::NonlinearFactorGraph
Definition: NonlinearFactorGraph.h:55
gtsam::Rot3::toQuaternion
gtsam::Quaternion toQuaternion() const
Definition: Rot3M.cpp:232
gtsam::Pose3::translation
const Point3 & translation(OptionalJacobian< 3, 6 > Hself={}) const
get translation
Definition: Pose3.cpp:324
gtsam::NonlinearFactorGraph::addPrior
void addPrior(Key key, const T &prior, const SharedNoiseModel &model=nullptr)
Definition: NonlinearFactorGraph.h:199
gtsam::LevenbergMarquardtOptimizer
Definition: LevenbergMarquardtOptimizer.h:35
Symbol.h
gtsam::ImuFactor
Definition: ImuFactor.h:169
gtsam::symbol_shorthand::B
Key B(std::uint64_t j)
Definition: inference/Symbol.h:149
ceres::pow
Jet< T, N > pow(const Jet< T, N > &f, double g)
Definition: jet.h:570
ISAM2.h
Incremental update functionality (ISAM2) for BayesTree, with fluid relinearization.
gtsam::imuBias::ConstantBias
Definition: ImuBias.h:32
gtsam::Pose3::rotation
const Rot3 & rotation(OptionalJacobian< 3, 6 > Hself={}) const
get rotation
Definition: Pose3.cpp:330
Eigen::Quaternion
The quaternion class used to represent 3D orientations and rotations.
Definition: ForwardDeclarations.h:293
gtsam
traits
Definition: SFMdata.h:40
NonlinearFactorGraph.h
Factor Graph consisting of non-linear factors.
gtsam::Values
Definition: Values.h:65
std
Definition: BFloat16.h:88
gtsam::Values::clear
void clear()
Definition: Values.h:347
p
float * p
Definition: Tutorial_Map_using.cpp:9
gtsam::Values::insert
void insert(Key j, const Value &val)
Definition: Values.cpp:156
gtsam::Point3
Vector3 Point3
Definition: Point3.h:38
V
MatrixXcd V
Definition: EigenSolver_EigenSolver_MatrixType.cpp:15
gtsam::noiseModel::Isotropic::Sigma
static shared_ptr Sigma(size_t dim, double sigma, bool smart=true)
Definition: NoiseModel.cpp:625
CombinedImuFactor.h
gtsam::findExampleDataFile
GTSAM_EXPORT std::string findExampleDataFile(const std::string &name)
Definition: dataset.cpp:70
output_filename
const string output_filename
Definition: IMUKittiExampleGPS.cpp:70
imuParams
std::shared_ptr< PreintegratedCombinedMeasurements::Params > imuParams()
Definition: ImuFactorsExample.cpp:86
gtsam::FactorGraph::add
IsDerived< DERIVEDFACTOR > add(std::shared_ptr< DERIVEDFACTOR > factor)
add is a synonym for push_back.
Definition: FactorGraph.h:171
graph
NonlinearFactorGraph graph
Definition: doc/Code/OdometryExample.cpp:2
gtsam::NavState::pose
const Pose3 pose() const
Definition: NavState.h:90
GPSFactor.h
Header file for GPS factor.
gtsam::symbol_shorthand::V
Key V(std::uint64_t j)
Definition: inference/Symbol.h:169
matlab_wrap.file
file
Definition: matlab_wrap.py:57
test_callbacks.value
value
Definition: test_callbacks.py:160
i
int i
Definition: BiCGSTAB_step_by_step.cpp:9
gtsam::GPSFactor
Definition: GPSFactor.h:35
ImuFactor.h
gtsam::BetweenFactor
Definition: BetweenFactor.h:40


gtsam
Author(s):
autogenerated on Wed Jan 1 2025 04:01:39