blob: 145582109da63127bb52d2c626e7331d3464763e [file] [log] [blame]
Brian Silvermandac0a4b2020-06-23 17:03:09 -07001#ifndef AOS_CONTROLS_QUATERNION_UTILS_H_
2#define AOS_CONTROLS_QUATERNION_UTILS_H_
3
4#include "Eigen/Dense"
5#include "Eigen/Geometry"
6#include "glog/logging.h"
7
8namespace aos {
9namespace controls {
10
11// Function to compute the quaternion average of a bunch of quaternions. Each
12// column in the input matrix is a quaternion (optionally scaled by it's
13// weight).
14template <int SM>
15inline Eigen::Matrix<double, 4, 1> QuaternionMean(
16 Eigen::Matrix<double, 4, SM> input) {
17 // Algorithm to compute the average of a bunch of quaternions:
18 // http://www.acsu.buffalo.edu/~johnc/ave_quat07.pdf
19
20 Eigen::Matrix<double, 4, 4> m = input * input.transpose();
21
22 Eigen::EigenSolver<Eigen::Matrix<double, 4, 4>> solver;
23 solver.compute(m);
24
25 Eigen::EigenSolver<Eigen::Matrix<double, 4, 4>>::EigenvectorsType
26 eigenvectors = solver.eigenvectors();
27 Eigen::EigenSolver<Eigen::Matrix<double, 4, 4>>::EigenvalueType eigenvalues =
28 solver.eigenvalues();
29
30 int max_index = 0;
31 double max_eigenvalue = 0.0;
32 for (int i = 0; i < 4; ++i) {
33 const double eigenvalue = std::abs(eigenvalues(i, 0));
34 if (eigenvalue > max_eigenvalue) {
35 max_eigenvalue = eigenvalue;
36 max_index = i;
37 }
38 }
39
40 // Assume that there shouldn't be any imaginary components to the eigenvector.
41 // I can't prove this is true, but everyone else seems to assume it...
42 // TODO(james): Handle this more rigorously.
43 for (int i = 0; i < 4; ++i) {
44 CHECK_LT(eigenvectors(i, max_index).imag(), 1e-4)
45 << eigenvectors(i, max_index);
46 }
47 return eigenvectors.col(max_index).real().normalized();
48}
49
50// Converts from a quaternion to a rotation vector, where the rotation vector's
51// direction represents the axis to rotate around and its magnitude represents
52// the number of radians to rotate.
53Eigen::Matrix<double, 3, 1> ToRotationVectorFromQuaternion(
54 const Eigen::Matrix<double, 4, 1> &X);
55
56inline Eigen::Matrix<double, 3, 1> ToRotationVectorFromQuaternion(
57 const Eigen::Quaternion<double> &X) {
58 return ToRotationVectorFromQuaternion(X.coeffs());
59}
60
61// Converts from a rotation vector to a quaternion. If you supply max_angle_cap,
62// then the rotation vector's magnitude will be clipped to be no more than
63// max_angle_cap before being converted to a quaternion.
64Eigen::Matrix<double, 4, 1> ToQuaternionFromRotationVector(
65 const Eigen::Matrix<double, 3, 1> &X,
66 const double max_angle_cap = std::numeric_limits<double>::infinity());
67
68} // namespace controls
69} // namespace aos
70
71#endif // AOS_CONTROLS_QUATERNION_UTILS_H_