blob: bce78d0c6cf3056cd4e37b36368e4d6a1606e989 [file] [log] [blame]
James Kuszmaul61750662021-06-21 21:32:33 -07001#include "frc971/control_loops/quaternion_utils.h"
Brian Silvermandac0a4b2020-06-23 17:03:09 -07002
3#include "Eigen/Dense"
4#include "Eigen/Geometry"
5
James Kuszmaul61750662021-06-21 21:32:33 -07006namespace frc971 {
Brian Silvermandac0a4b2020-06-23 17:03:09 -07007namespace controls {
milind-ue53bf552021-12-11 14:42:00 -08008namespace {
Brian Silvermandac0a4b2020-06-23 17:03:09 -07009
milind-ue53bf552021-12-11 14:42:00 -080010double SinXoverX(double x) {
11 const double xsquared = x * x;
Brian Silvermandac0a4b2020-06-23 17:03:09 -070012
13 // sin(x)/x = 1
14 double sinx_x = 1.0;
15
16 // - x^2/3!
milind-ue53bf552021-12-11 14:42:00 -080017 double value = xsquared / 6.0;
Brian Silvermandac0a4b2020-06-23 17:03:09 -070018 sinx_x -= value;
19
20 // + x^4/5!
milind-ue53bf552021-12-11 14:42:00 -080021 value = value * xsquared / 20.0;
Brian Silvermandac0a4b2020-06-23 17:03:09 -070022 sinx_x += value;
23
24 // - x^6/7!
milind-ue53bf552021-12-11 14:42:00 -080025 value = value * xsquared / (6.0 * 7.0);
Brian Silvermandac0a4b2020-06-23 17:03:09 -070026 sinx_x -= value;
27
28 // + x^8/9!
milind-ue53bf552021-12-11 14:42:00 -080029 value = value * xsquared / (8.0 * 9.0);
Brian Silvermandac0a4b2020-06-23 17:03:09 -070030 sinx_x += value;
31
32 // - x^10/11!
milind-ue53bf552021-12-11 14:42:00 -080033 value = value * xsquared / (10.0 * 11.0);
Brian Silvermandac0a4b2020-06-23 17:03:09 -070034 sinx_x -= value;
35
36 // + x^12/13!
milind-ue53bf552021-12-11 14:42:00 -080037 value = value * xsquared / (12.0 * 13.0);
Brian Silvermandac0a4b2020-06-23 17:03:09 -070038 sinx_x += value;
39
40 // - x^14/15!
milind-ue53bf552021-12-11 14:42:00 -080041 value = value * xsquared / (14.0 * 15.0);
Brian Silvermandac0a4b2020-06-23 17:03:09 -070042 sinx_x -= value;
43
44 // + x^16/17!
milind-ue53bf552021-12-11 14:42:00 -080045 value = value * xsquared / (16.0 * 17.0);
Brian Silvermandac0a4b2020-06-23 17:03:09 -070046 sinx_x += value;
47
milind-ue53bf552021-12-11 14:42:00 -080048 return sinx_x;
49
Brian Silvermandac0a4b2020-06-23 17:03:09 -070050 // To plot the residual in matplotlib, run:
51 // import numpy
52 // import scipy
53 // from matplotlib import pyplot
54 // x = numpy.arange(-numpy.pi, numpy.pi, 0.01)
55 // pyplot.plot(x, 1 - x**2 / scipy.misc.factorial(3) +
56 // x**4 / scipy.misc.factorial(5) -
57 // x**6 / scipy.misc.factorial(7) +
58 // x**8 / scipy.misc.factorial(9) -
59 // x ** 10 / scipy.misc.factorial(11) +
60 // x ** 12 / scipy.misc.factorial(13) -
61 // x ** 14 / scipy.misc.factorial(15) +
62 // x ** 16 / scipy.misc.factorial(17) -
63 // numpy.sin(x) / x)
Brian Silvermandac0a4b2020-06-23 17:03:09 -070064}
65
milind-ue53bf552021-12-11 14:42:00 -080066} // namespace
67
Brian Silvermandac0a4b2020-06-23 17:03:09 -070068inline Eigen::Matrix<double, 4, 1> MaybeFlipX(
69 const Eigen::Matrix<double, 4, 1> &X) {
70 if (X(3, 0) < 0.0) {
71 return -X;
72 } else {
73 return X;
74 }
75}
76
milind-ue53bf552021-12-11 14:42:00 -080077Eigen::Matrix<double, 4, 1> ToQuaternionFromRotationVector(
78 const Eigen::Matrix<double, 3, 1> &X, const double max_angle_cap) {
79 const double unclipped_angle = X.norm();
80 const double angle_scalar =
81 (unclipped_angle > max_angle_cap) ? max_angle_cap / unclipped_angle : 1.0;
82 const double angle = unclipped_angle * angle_scalar;
83 const double half_angle = angle * 0.5;
84
85 const double scalar = SinXoverX(half_angle) * 0.5;
86
87 Eigen::Matrix<double, 4, 1> result;
88 result.block<3, 1>(0, 0) = X * scalar * angle_scalar;
89 result(3, 0) = std::cos(half_angle);
90 return result;
91}
92
93// q = cos(a/2) + i ( x * sin(a/2)) + j (y * sin(a/2)) + k ( z * sin(a/2))
94
Brian Silvermandac0a4b2020-06-23 17:03:09 -070095Eigen::Matrix<double, 3, 1> ToRotationVectorFromQuaternion(
96 const Eigen::Matrix<double, 4, 1> &X) {
97 // TODO(austin): Verify we still need it.
98 const Eigen::Matrix<double, 4, 1> corrected_X = MaybeFlipX(X);
99 const double half_angle =
100 std::atan2(corrected_X.block<3, 1>(0, 0).norm(), corrected_X(3, 0));
101
milind-ue53bf552021-12-11 14:42:00 -0800102 const double scalar = 2.0 / SinXoverX(half_angle);
Brian Silvermandac0a4b2020-06-23 17:03:09 -0700103
104 return corrected_X.block<3, 1>(0, 0) * scalar;
105}
106
milind-ue53bf552021-12-11 14:42:00 -0800107Eigen::Matrix<double, 4, 3> QuaternionDerivativeDerivitive(
108 const Eigen::Vector4d &q_matrix) {
109 // qa * qb = (a.w() * b.x() + a.x() * b.w() + a.y() * b.z() - a.z() * b.y(),
110 // a.w() * b.y() + a.y() * b.w() + a.z() * b.x() - a.x() * b.z(),
111 // a.w() * b.z() + a.z() * b.w() + a.x() * b.y() - a.y() * b.x(),
112 // a.w() * b.w() - a.x() * b.x() - a.y() * b.y() - a.z() * b.z())
113 //
114 // We want q * omega_q = result * omega.
115 Eigen::Matrix<double, 4, 3> result;
116 result(3, 0) = -q_matrix.x() * 0.5;
117 result(3, 1) = -q_matrix.y() * 0.5;
118 result(3, 2) = -q_matrix.z() * 0.5;
119
120 result(0, 0) = q_matrix.w() * 0.5;
121 result(0, 1) = -q_matrix.z() * 0.5;
122 result(0, 2) = q_matrix.y() * 0.5;
123
124 result(1, 0) = q_matrix.z() * 0.5;
125 result(1, 1) = q_matrix.w() * 0.5;
126 result(1, 2) = -q_matrix.x() * 0.5;
127
128 result(2, 0) = -q_matrix.y() * 0.5;
129 result(2, 1) = q_matrix.x() * 0.5;
130 result(2, 2) = q_matrix.w() * 0.5;
131
132 return result;
133}
134
Brian Silvermandac0a4b2020-06-23 17:03:09 -0700135} // namespace controls
James Kuszmaul61750662021-06-21 21:32:33 -0700136} // namespace frc971