Calico
A visual-inertial calibration library designed for rapid problem construction and debugging.
gyroscope_cost_functor.h
1 #ifndef CALICO_SENSORS_GYROSCOPE_COST_FUNCTOR_H_
2 #define CALICO_SENSORS_GYROSCOPE_COST_FUNCTOR_H_
3 
4 #include "calico/geometry.h"
5 #include "calico/sensors/gyroscope_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 gyroscope cost function.
13 enum class GyroscopeParameterIndices : int {
14  // Gyroscope intrinsics.
15  kIntrinsicsIndex = 0,
16  // Extrinsics parameters of the gyroscope relative to its sensor rig.
17  kExtrinsicsRotationIndex = 1,
18  kExtrinsicsTranslationIndex = 2,
19  // Sensor latency.
20  kLatencyIndex = 3,
21  // Rotation and position control points of the appropriate spline segment as an
22  // Nx6 matrix.
23  kSensorRigPoseSplineControlPointsIndex = 4
24 };
25 
26 // Generic auto-differentiation gyroscope cost functor. Residuals will be based on
27 // how the gyroscope model is initialized.
29  public:
30  static constexpr int kGyroscopeResidualSize = 3;
31  explicit GyroscopeCostFunctor(
32  GyroscopeIntrinsicsModel gyroscope_model,
33  const Eigen::Vector3d& measurement, double sigma, double stamp,
34  const Trajectory& sp_T_world_sensorrig);
35 
36  // Convenience function for creating a gyroscope cost function.
37  static ceres::CostFunction* CreateCostFunction(
38  const Eigen::Vector3d& measurement, double sigma,
39  GyroscopeIntrinsicsModel gyroscope_model, Eigen::VectorXd& intrinsics,
40  Pose3d& extrinsics, double& latency,
41  Trajectory& trajectory_world_sensorrig, double stamp,
42  std::vector<double*>& parameters);
43 
44  // Parameters to the cost function:
45  // intrinsics:
46  // All parameters in the intrinsics model as an Eigen column vector.
47  // Order of the parameters will need to be in agreement with the model
48  // being used.
49  // q_sensorrig_gyroscope:
50  // Rotation from sensorrig frame to gyroscope frame as a quaternion.
51  // t_sensorrig_gyroscope:
52  // Position of gyroscope relative to sensorrig origin resolved in the
53  // sensorrig frame.
54  // latency:
55  // Sensor latency in seconds.
56  // control_points:
57  // Control points for the entire pose trajectory.
58  template <typename T>
59  bool operator()(T const* const* parameters, T* residual) {
60  // Parse intrinsics.
61  const T* intrinsics_ptr =
62  static_cast<const T*>(&(parameters[static_cast<int>(
63  GyroscopeParameterIndices::kIntrinsicsIndex)][0]));
64  const int parameter_size = gyroscope_model_->NumberOfParameters();
65  const Eigen::VectorX<T> intrinsics = Eigen::Map<const Eigen::VectorX<T>>(
66  intrinsics_ptr, parameter_size);
67  // Parse extrinsics.
68  const Eigen::Map<const Eigen::Quaternion<T>> q_sensorrig_gyroscope(
69  &(parameters[static_cast<int>(
70  GyroscopeParameterIndices::kExtrinsicsRotationIndex)][0]));
71  const Eigen::Map<const Eigen::Vector3<T>> t_sensorrig_gyroscope(
72  &(parameters[static_cast<int>(
73  GyroscopeParameterIndices::kExtrinsicsTranslationIndex)][0]));
74  // Parse latency.
75  const T latency =
76  parameters[static_cast<int>(
77  GyroscopeParameterIndices::kLatencyIndex)][0];
78  // Parse sensor rig spline resolved in the world frame.
79  const int num_rotation_control_points =
80  rotation_trajectory_evaluation_params_.num_control_points;
81  Eigen::MatrixX<T> rotation_control_points(num_rotation_control_points, 3);
82  for (int i = 0; i < num_rotation_control_points; ++i) {
83  rotation_control_points.row(i) = Eigen::Map<const Eigen::Vector3<T>>(
84  &(parameters[static_cast<int>(
85  GyroscopeParameterIndices::kSensorRigPoseSplineControlPointsIndex)
86  + i
87  ][0]));
88  }
89  const int num_position_control_points =
90  position_trajectory_evaluation_params_.num_control_points;
91  Eigen::MatrixX<T> position_control_points(num_position_control_points, 3);
92  for (int i = 0; i < num_position_control_points; ++i) {
93  position_control_points.row(i) = Eigen::Map<const Eigen::Vector3<T>>(
94  &(parameters[static_cast<int>(
95  GyroscopeParameterIndices::kSensorRigPoseSplineControlPointsIndex)
96  + i + num_rotation_control_points
97  ][0]));
98  }
99 
100  const Eigen::MatrixX<T> rotation_basis_matrix =
101  rotation_trajectory_evaluation_params_.basis_matrix.template cast<T>();
102  const T rotation_knot0 = static_cast<T>(
103  rotation_trajectory_evaluation_params_.knot0);
104  const T rotation_knot1 = static_cast<T>(
105  rotation_trajectory_evaluation_params_.knot1);
106  const T rotation_stamp =
107  static_cast<T>(rotation_trajectory_evaluation_params_.stamp) - latency;
108 
109  const Eigen::MatrixX<T> position_basis_matrix =
110  position_trajectory_evaluation_params_.basis_matrix.template cast<T>();
111  const T position_knot0 = static_cast<T>(
112  position_trajectory_evaluation_params_.knot0);
113  const T position_knot1 = static_cast<T>(
114  position_trajectory_evaluation_params_.knot1);
115  const T position_stamp =
116  static_cast<T>(position_trajectory_evaluation_params_.stamp) - latency;
117 
118  // Evaluate the pose and pose rate.
119  const Eigen::Vector3<T> phi_sensorrig_world = -BSpline<3, T>::Evaluate(
120  rotation_control_points, rotation_knot0, rotation_knot1,
121  rotation_basis_matrix, rotation_stamp, 0);
122  T q_sensorrig_world_array[4];
123  ceres::AngleAxisToQuaternion(
124  phi_sensorrig_world.data(), q_sensorrig_world_array);
125  const Eigen::Quaternion<T> q_sensorrig_world(
126  q_sensorrig_world_array[0], q_sensorrig_world_array[1],
127  q_sensorrig_world_array[2], q_sensorrig_world_array[3]);
128  const Eigen::Vector3<T> t_world_sensorrig = BSpline<3, T>::Evaluate(
129  position_control_points, position_knot0, position_knot1,
130  position_basis_matrix, position_stamp, /*derivative=*/0);
131  const Eigen::Vector3<T> phi_dot_sensorrig_world = -BSpline<3, T>::Evaluate(
132  rotation_control_points, rotation_knot0, rotation_knot1,
133  rotation_basis_matrix, rotation_stamp, 1);
134 
135  const Eigen::Matrix3<T> J = ExpSO3Jacobian(phi_sensorrig_world);
136  const Eigen::Vector3<T> omega_sensorrig_world = J * phi_dot_sensorrig_world;
137  const Eigen::Vector3<T> omega_gyroscope_world =
138  -(q_sensorrig_gyroscope.inverse() * omega_sensorrig_world);
139  // Project the sensor angular velocity through the gyroscope model.
140  const absl::StatusOr<Eigen::Vector3<T>> projection =
141  gyroscope_model_->Project(intrinsics, omega_gyroscope_world);
142  if (projection.ok()) {
143  Eigen::Map<Eigen::Vector3<T>> error(residual);
144  const Eigen::Vector3<T> measurement = measurement_.template cast<T>();
145  error = (measurement - *projection) * static_cast<T>(information_);
146  return true;
147  }
148  return false;
149  }
150 
151  private:
152  Eigen::Vector3d measurement_;
153  double information_;
154  std::unique_ptr<GyroscopeModel> gyroscope_model_;
155  TrajectoryEvaluationParams position_trajectory_evaluation_params_;
156  TrajectoryEvaluationParams rotation_trajectory_evaluation_params_;
157 };
158 } // namespace calico::sensors
159 #endif // CALICO_SENSORS_GYROSCOPE_COST_FUNCTOR_H_
Definition: bspline.h:17
Definition: trajectory.h:25
Definition: gyroscope_cost_functor.h:28
Sensors namespace.
Definition: accelerometer.cpp:8
GyroscopeIntrinsicsModel
Gyroscope model types.
Definition: gyroscope_models.h:16
Eigen::Matrix3< T > ExpSO3Jacobian(const Eigen::Vector3< T > &phi)
Definition: geometry.h:138
Definition: trajectory.h:14