Calico
A visual-inertial calibration library designed for rapid problem construction and debugging.
accelerometer_cost_functor.h
1 #ifndef CALICO_SENSORS_ACCELEROMETER_COST_FUNCTOR_H_
2 #define CALICO_SENSORS_ACCELEROMETER_COST_FUNCTOR_H_
3 
4 #include "calico/geometry.h"
5 #include "calico/sensors/accelerometer_models.h"
6 #include "calico/trajectory.h"
7 #include "ceres/cost_function.h"
8 
9 
10 namespace calico::sensors {
11 
12 // Enum listing the positions of parameters for a accelerometer cost function.
13 enum class AccelerometerParameterIndices : int {
14  // Accelerometer intrinsics.
15  kIntrinsicsIndex = 0,
16  // Extrinsics parameters of the accelerometer relative to its sensor rig.
17  kExtrinsicsRotationIndex = 1,
18  kExtrinsicsTranslationIndex = 2,
19  // Sensor latency.
20  kLatencyIndex = 3,
21  // Gravity vector.
22  kGravityIndex = 4,
23  // Rotation and position control points of the appropriate spline segment as an
24  // Nx6 matrix.
25  kSensorRigPoseSplineControlPointsIndex = 5
26 };
27 
28 // Generic auto-differentiation accelerometer cost functor. Residuals will be based on
29 // how the accelerometer model is initialized.
31  public:
32  static constexpr int kAccelerometerResidualSize = 3;
33  explicit AccelerometerCostFunctor(
34  AccelerometerIntrinsicsModel accelerometer_model,
35  const Eigen::Vector3d& measurement, double sigma, double stamp,
36  const Trajectory& sp_T_world_sensorrig);
37 
38  // Convenience function for creating a accelerometer cost function.
39  static ceres::CostFunction* CreateCostFunction(
40  const Eigen::Vector3d& measurement, double sigma,
41  AccelerometerIntrinsicsModel accelerometer_model,
42  Eigen::VectorXd& intrinsics, Pose3d& extrinsics, double& latency,
43  Eigen::Vector3d& gravity, Trajectory& trajectory_world_sensorrig,
44  double stamp, std::vector<double*>& parameters);
45 
46  // Parameters to the cost function:
47  // intrinsics:
48  // All parameters in the intrinsics model as an Eigen column vector.
49  // Order of the parameters will need to be in agreement with the model
50  // being used.
51  // q_sensorrig_accelerometer:
52  // Rotation from sensorrig frame to accelerometer frame as a quaternion.
53  // t_sensorrig_accelerometer:
54  // Position of accelerometer relative to sensorrig origin resolved in the
55  // sensorrig frame.
56  // latency:
57  // Sensor latency in seconds.
58  // gravity:
59  // Gravity vector resolved in the world frame.
60  // control_points:
61  // Control points for the entire pose trajectory.
62  template <typename T>
63  bool operator()(T const* const* parameters, T* residual) {
64  // Parse intrinsics.
65  const T* intrinsics_ptr =
66  static_cast<const T*>(&(parameters[static_cast<int>(
67  AccelerometerParameterIndices::kIntrinsicsIndex)][0]));
68  const int parameter_size = accelerometer_model_->NumberOfParameters();
69  const Eigen::VectorX<T> intrinsics = Eigen::Map<const Eigen::VectorX<T>>(
70  intrinsics_ptr, parameter_size);
71  // Parse extrinsics.
72  const Eigen::Map<const Eigen::Quaternion<T>> q_sensorrig_accelerometer(
73  &(parameters[static_cast<int>(
74  AccelerometerParameterIndices::kExtrinsicsRotationIndex)][0]));
75  const Eigen::Map<const Eigen::Vector3<T>> t_sensorrig_accelerometer(
76  &(parameters[static_cast<int>(
77  AccelerometerParameterIndices::kExtrinsicsTranslationIndex)][0]));
78  // Parse latency.
79  const T latency =
80  parameters[static_cast<int>(
81  AccelerometerParameterIndices::kLatencyIndex)][0];
82  // Parse gravity.
83  const Eigen::Map<const Eigen::Vector3<T>> gravity(
84  &(parameters[static_cast<int>(
85  AccelerometerParameterIndices::kGravityIndex)][0]));
86  // Parse sensor rig spline resolved in the world frame.
87  const int num_rotation_control_points =
88  rotation_trajectory_evaluation_params_.num_control_points;
89  Eigen::MatrixX<T> rotation_control_points(num_rotation_control_points, 3);
90  for (int i = 0; i < num_rotation_control_points; ++i) {
91  rotation_control_points.row(i) = Eigen::Map<const Eigen::Vector3<T>>(
92  &(parameters[static_cast<int>(
93  AccelerometerParameterIndices::kSensorRigPoseSplineControlPointsIndex)
94  + i
95  ][0]));
96  }
97  const int num_position_control_points =
98  position_trajectory_evaluation_params_.num_control_points;
99  Eigen::MatrixX<T> position_control_points(num_position_control_points, 3);
100  for (int i = 0; i < num_position_control_points; ++i) {
101  position_control_points.row(i) = Eigen::Map<const Eigen::Vector3<T>>(
102  &(parameters[static_cast<int>(
103  AccelerometerParameterIndices::kSensorRigPoseSplineControlPointsIndex)
104  + i + num_rotation_control_points
105  ][0]));
106  }
107 
108  const Eigen::MatrixX<T> rotation_basis_matrix =
109  rotation_trajectory_evaluation_params_.basis_matrix.template cast<T>();
110  const T rotation_knot0 = static_cast<T>(
111  rotation_trajectory_evaluation_params_.knot0);
112  const T rotation_knot1 = static_cast<T>(
113  rotation_trajectory_evaluation_params_.knot1);
114  const T rotation_stamp =
115  static_cast<T>(rotation_trajectory_evaluation_params_.stamp) - latency;
116 
117  const Eigen::MatrixX<T> position_basis_matrix =
118  position_trajectory_evaluation_params_.basis_matrix.template cast<T>();
119  const T position_knot0 = static_cast<T>(
120  position_trajectory_evaluation_params_.knot0);
121  const T position_knot1 = static_cast<T>(
122  position_trajectory_evaluation_params_.knot1);
123  const T position_stamp =
124  static_cast<T>(position_trajectory_evaluation_params_.stamp) - latency;
125 
126  // Evaluate the pose, pose rate, and pose acceleration.
127  const Eigen::Vector3<T> phi_sensorrig_world = -BSpline<3, T>::Evaluate(
128  rotation_control_points, rotation_knot0, rotation_knot1,
129  rotation_basis_matrix, rotation_stamp, 0);
130  T q_sensorrig_world_array[4];
131  ceres::AngleAxisToQuaternion(
132  phi_sensorrig_world.data(), q_sensorrig_world_array);
133  const Eigen::Quaternion<T> q_sensorrig_world(
134  q_sensorrig_world_array[0], q_sensorrig_world_array[1],
135  q_sensorrig_world_array[2], q_sensorrig_world_array[3]);
136  const Eigen::Vector3<T> t_world_sensorrig = BSpline<3, T>::Evaluate(
137  position_control_points, position_knot0, position_knot1,
138  position_basis_matrix, position_stamp, 0);
139  const Eigen::Vector3<T> phi_dot_sensorrig_world = -BSpline<3, T>::Evaluate(
140  rotation_control_points, rotation_knot0, rotation_knot1,
141  rotation_basis_matrix, rotation_stamp, 1);
142  const Eigen::Vector3<T> phi_ddot_sensorrig_world = -BSpline<3, T>::Evaluate(
143  rotation_control_points, rotation_knot0, rotation_knot1,
144  rotation_basis_matrix, rotation_stamp, 2);
145  const Eigen::Vector3<T> ddt_world_sensorrig = BSpline<3, T>::Evaluate(
146  position_control_points, position_knot0, position_knot1,
147  position_basis_matrix, position_stamp, 2);
148 
149  // Compute the kinematics of the accelerometer.
150  const Eigen::Matrix3<T> J_sensorrig_world =
151  ExpSO3Jacobian(phi_sensorrig_world);
152  const Eigen::Matrix3<T> J_dot_sensorrig_world =
153  ExpSO3JacobianDot(phi_sensorrig_world, phi_dot_sensorrig_world);
154  const Eigen::Vector3<T> omega_sensorrig_world =
155  J_sensorrig_world * phi_dot_sensorrig_world;
156  const Eigen::Vector3<T> alpha_sensorrig_world =
157  J_dot_sensorrig_world * phi_dot_sensorrig_world +
158  J_sensorrig_world * phi_ddot_sensorrig_world;
159  const Eigen::Matrix3<T> Alpha = -Skew(alpha_sensorrig_world);
160  const Eigen::Matrix3<T> Omega = -Skew(omega_sensorrig_world);
161  const Eigen::Vector3<T> ddt_accelerometer_world_accelerometer =
162  q_sensorrig_accelerometer.inverse() *
163  (q_sensorrig_world * (ddt_world_sensorrig - gravity) +
164  (Omega * Omega + Alpha) * t_sensorrig_accelerometer);
165  // Project the sensor angular velocity through the accelerometer model.
166  const absl::StatusOr<Eigen::Vector3<T>> projection =
167  accelerometer_model_->Project(
168  intrinsics, ddt_accelerometer_world_accelerometer);
169  if (projection.ok()) {
170  Eigen::Map<Eigen::Vector3<T>> error(residual);
171  const Eigen::Vector3<T> measurement = measurement_.template cast<T>();
172  error = (measurement - *projection) * static_cast<T>(information_);
173  return true;
174  }
175  return false;
176  }
177 
178  private:
179  Eigen::Vector3d measurement_;
180  double information_;
181  std::unique_ptr<AccelerometerModel> accelerometer_model_;
182  TrajectoryEvaluationParams position_trajectory_evaluation_params_;
183  TrajectoryEvaluationParams rotation_trajectory_evaluation_params_;
184 };
185 } // namespace calico::sensors
186 #endif // CALICO_SENSORS_ACCELEROMETER_COST_FUNCTOR_H_
Definition: bspline.h:17
Definition: trajectory.h:25
Definition: accelerometer_cost_functor.h:30
Sensors namespace.
Definition: accelerometer.cpp:8
AccelerometerIntrinsicsModel
Accelerometer model types.
Definition: accelerometer_models.h:16
Eigen::Matrix3< T > Skew(const Eigen::Vector3< T > &v)
Convert a 3-vector to a skew-symmetric cross-product matrix.
Definition: geometry.h:12
Eigen::Matrix3< T > ExpSO3Jacobian(const Eigen::Vector3< T > &phi)
Definition: geometry.h:138
Eigen::Matrix3< T > ExpSO3JacobianDot(const Eigen::Vector3< T > &phi, const Eigen::Vector3< T > &phi_dot)
Compute the time derivative of the Rodrigues formula manifold Jacobian.
Definition: geometry.h:214
Definition: trajectory.h:14