FullIMUFactor.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /**
  2. * @file FullIMUFactor.h
  3. * @brief Factor to express an IMU measurement between dynamic poses
  4. * @author Alex Cunningham
  5. */
  6. #pragma once
  7. #include <gtsam/base/numericalDerivative.h>
  8. #include <gtsam/nonlinear/NonlinearFactor.h>
  9. #include <gtsam_unstable/dynamics/PoseRTV.h>
  10. #include <boost/bind/bind.hpp>
  11. namespace gtsam {
  12. /**
  13. * Class that represents integrating IMU measurements over time for dynamic systems
  14. * This factor has dimension 9, with a built-in constraint for velocity modeling
  15. *
  16. * Templated to allow for different key types, but variables all
  17. * assumed to be PoseRTV
  18. */
  19. template<class POSE>
  20. class FullIMUFactor : public NoiseModelFactor2<POSE, POSE> {
  21. public:
  22. typedef NoiseModelFactor2<POSE, POSE> Base;
  23. typedef FullIMUFactor<POSE> This;
  24. protected:
  25. /** measurements from the IMU */
  26. Vector3 accel_, gyro_;
  27. double dt_; /// time between measurements
  28. public:
  29. /** Standard constructor */
  30. FullIMUFactor(const Vector3& accel, const Vector3& gyro,
  31. double dt, const Key& key1, const Key& key2, const SharedNoiseModel& model)
  32. : Base(model, key1, key2), accel_(accel), gyro_(gyro), dt_(dt) {
  33. assert(model->dim() == 9);
  34. }
  35. /** Single IMU vector - imu = [accel, gyro] */
  36. FullIMUFactor(const Vector6& imu,
  37. double dt, const Key& key1, const Key& key2, const SharedNoiseModel& model)
  38. : Base(model, key1, key2), accel_(imu.head(3)), gyro_(imu.tail(3)), dt_(dt) {
  39. assert(imu.size() == 6);
  40. assert(model->dim() == 9);
  41. }
  42. ~FullIMUFactor() override {}
  43. /// @return a deep copy of this factor
  44. gtsam::NonlinearFactor::shared_ptr clone() const override {
  45. return boost::static_pointer_cast<gtsam::NonlinearFactor>(
  46. gtsam::NonlinearFactor::shared_ptr(new This(*this))); }
  47. /** Check if two factors are equal */
  48. bool equals(const NonlinearFactor& e, double tol = 1e-9) const override {
  49. const This* const f = dynamic_cast<const This*>(&e);
  50. return f && Base::equals(e) &&
  51. equal_with_abs_tol(accel_, f->accel_, tol) &&
  52. equal_with_abs_tol(gyro_, f->gyro_, tol) &&
  53. std::abs(dt_ - f->dt_) < tol;
  54. }
  55. void print(const std::string& s="", const gtsam::KeyFormatter& formatter = gtsam::DefaultKeyFormatter) const override {
  56. std::string a = "FullIMUFactor: " + s;
  57. Base::print(a, formatter);
  58. gtsam::print((Vector)accel_, "accel");
  59. gtsam::print((Vector)gyro_, "gyro");
  60. std::cout << "dt: " << dt_ << std::endl;
  61. }
  62. // access
  63. const Vector3& gyro() const { return gyro_; }
  64. const Vector3& accel() const { return accel_; }
  65. Vector6 z() const { return (Vector(6) << accel_, gyro_).finished(); }
  66. /**
  67. * Error evaluation with optional derivatives - calculates
  68. * z - h(x1,x2)
  69. */
  70. Vector evaluateError(const PoseRTV& x1, const PoseRTV& x2,
  71. boost::optional<Matrix&> H1 = boost::none,
  72. boost::optional<Matrix&> H2 = boost::none) const override {
  73. Vector9 z;
  74. z.head(3).operator=(accel_); // Strange syntax to work around ambiguous operator error with clang
  75. z.segment(3, 3).operator=(gyro_); // Strange syntax to work around ambiguous operator error with clang
  76. z.tail(3).operator=(x2.t()); // Strange syntax to work around ambiguous operator error with clang
  77. if (H1) *H1 = numericalDerivative21<Vector9, PoseRTV, PoseRTV>(
  78. std::bind(This::predict_proxy, std::placeholders::_1, std::placeholders::_2, dt_), x1, x2, 1e-5);
  79. if (H2) *H2 = numericalDerivative22<Vector9, PoseRTV, PoseRTV>(
  80. std::bind(This::predict_proxy, std::placeholders::_1, std::placeholders::_2, dt_), x1, x2, 1e-5);
  81. return z - predict_proxy(x1, x2, dt_);
  82. }
  83. /** dummy version that fails for non-dynamic poses */
  84. virtual Vector evaluateError(const Pose3& x1, const Pose3& x2,
  85. boost::optional<Matrix&> H1 = boost::none,
  86. boost::optional<Matrix&> H2 = boost::none) const {
  87. assert(false);
  88. return Vector6::Zero();
  89. }
  90. private:
  91. /** copy of the measurement function formulated for numerical derivatives */
  92. static Vector9 predict_proxy(const PoseRTV& x1, const PoseRTV& x2, double dt) {
  93. Vector9 hx;
  94. hx.head(6).operator=(x1.imuPrediction(x2, dt)); // Strange syntax to work around ambiguous operator error with clang
  95. hx.tail(3).operator=(x1.translationIntegration(x2, dt)); // Strange syntax to work around ambiguous operator error with clang
  96. return hx;
  97. }
  98. };
  99. } // \namespace gtsam