Program Listing for File inertial-error-term.h

Return to documentation for file (algorithms/ceres-error-terms/include/ceres-error-terms/inertial-error-term.h)

#ifndef CERES_ERROR_TERMS_INERTIAL_ERROR_TERM_H_
#define CERES_ERROR_TERMS_INERTIAL_ERROR_TERM_H_

#include <vector>

#include <Eigen/Core>
#include <ceres/sized_cost_function.h>
#include <glog/logging.h>
#include <imu-integrator/imu-integrator.h>

#include <ceres-error-terms/common.h>

namespace ceres_error_terms {

typedef Eigen::Matrix<double, imu_integrator::kStateSize, 1>
    InertialStateVector;
typedef Eigen::Matrix<double, imu_integrator::kErrorStateSize,
                      imu_integrator::kErrorStateSize>
    InertialStateCovariance;
typedef Eigen::Matrix<double, imu_integrator::kErrorStateSize,
                      imu_integrator::kStateSize>
    InertialJacobianType;

struct InertialState {
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
  Eigen::Matrix<double, 4, 1> q_I_M;
  Eigen::Matrix<double, 3, 1> b_g;
  Eigen::Matrix<double, 3, 1> v_M;
  Eigen::Matrix<double, 3, 1> b_a;
  Eigen::Matrix<double, 3, 1> p_M_I;

  bool operator==(const InertialState& other) const {
    return (q_I_M == other.q_I_M) && (b_g == other.b_g) && (v_M == other.v_M) &&
           (b_a == other.b_a) && (p_M_I == other.p_M_I);
  }

  InertialStateVector toVector() const {
    InertialStateVector vector;
    vector << q_I_M, b_g, v_M, b_a, p_M_I;
    return vector;
  }

  static InertialState fromVector(const InertialStateVector& vector) {
    InertialState state;
    state.q_I_M = vector.head<imu_integrator::kStateOrientationBlockSize>();
    state.b_g = vector.segment<imu_integrator::kGyroBiasBlockSize>(
        imu_integrator::kStateGyroBiasOffset);
    state.v_M = vector.segment<imu_integrator::kVelocityBlockSize>(
        imu_integrator::kStateVelocityOffset);
    state.b_a = vector.segment<imu_integrator::kAccelBiasBlockSize>(
        imu_integrator::kStateAccelBiasOffset);
    state.p_M_I = vector.segment<imu_integrator::kPositionBlockSize>(
        imu_integrator::kStatePositionOffset);
    return state;
  }
};

struct ImuIntegration {
  ImuIntegration() : valid(false) {}
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
  InertialState begin_state;
  InertialState end_state;

  InertialStateCovariance phi_accum;
  InertialStateCovariance Q_accum;
  Eigen::LLT<InertialStateCovariance> L_cholesky_Q_accum;

  InertialJacobianType J_end;
  InertialJacobianType J_begin;

  bool valid;
};

// Note: this error term accepts rotations expressed as quaternions
// in JPL convention [x, y, z, w]. This convention corresponds to the internal
// coefficient storage of Eigen so you can directly pass pointer to your
// Eigen quaternion data, e.g. your_eigen_quaternion.coeffs().data().
class InertialErrorTerm
    : public ceres::SizedCostFunction<imu_integrator::kErrorStateSize,
                                      imu_integrator::kStatePoseBlockSize,
                                      imu_integrator::kGyroBiasBlockSize,
                                      imu_integrator::kVelocityBlockSize,
                                      imu_integrator::kAccelBiasBlockSize,
                                      imu_integrator::kStatePoseBlockSize,
                                      imu_integrator::kGyroBiasBlockSize,
                                      imu_integrator::kVelocityBlockSize,
                                      imu_integrator::kAccelBiasBlockSize> {
 public:
  InertialErrorTerm(
      const Eigen::Matrix<double, 6, Eigen::Dynamic>& imu_data,
      const Eigen::Matrix<int64_t, 1, Eigen::Dynamic>& imu_timestamps,
      double gyro_noise_sigma, double gyro_bias_sigma, double acc_noise_sigma,
      double acc_bias_sigma, double gravity_magnitude)
      : imu_timestamps_(imu_timestamps),
        imu_data_(imu_data),
        imu_covariance_cached_p_q_(nullptr),
        integrator_(
            gyro_noise_sigma, gyro_bias_sigma, acc_noise_sigma, acc_bias_sigma,
            gravity_magnitude) {
    CHECK_GT(imu_data.cols(), 0);
    CHECK_EQ(imu_data.cols(), imu_timestamps.cols());

    CHECK_GT(gyro_noise_sigma, 0.0);
    CHECK_GT(gyro_bias_sigma, 0.0);
    CHECK_GT(acc_noise_sigma, 0.0);
    CHECK_GT(acc_bias_sigma, 0.0);
  }

  virtual ~InertialErrorTerm() {}

  virtual bool Evaluate(
      double const* const* parameters, double* residuals_ptr,
      double** jacobians) const;

  inline void setCachedImuCovariancePointer(
      Eigen::Matrix<double, 6, 6>* imu_covariance_cached_p_q) {
    CHECK_NOTNULL(imu_covariance_cached_p_q);
    imu_covariance_cached_p_q_ = imu_covariance_cached_p_q;
  }

  EIGEN_MAKE_ALIGNED_OPERATOR_NEW

 private:
  void IntegrateStateAndCovariance(
      const InertialState& current_state,
      const Eigen::Matrix<int64_t, 1, Eigen::Dynamic>& imu_timestamps,
      const Eigen::Matrix<double, 6, Eigen::Dynamic>& imu_data,
      InertialState* next_state, InertialStateCovariance* phi_accum,
      InertialStateCovariance* Q_accum) const;

  const Eigen::Matrix<int64_t, 1, Eigen::Dynamic> imu_timestamps_;
  const Eigen::Matrix<double, 6, Eigen::Dynamic> imu_data_;
  Eigen::Matrix<double, 6, 6>* imu_covariance_cached_p_q_;

  const imu_integrator::ImuIntegratorRK4 integrator_;

  // Cache the IMU integration to avoid unnecessary integrations.
  mutable ImuIntegration integration_cache_;
};

}  // namespace ceres_error_terms

#endif  // CERES_ERROR_TERMS_INERTIAL_ERROR_TERM_H_