blob: dc5b411ffcabf1583a33327f01ad61a4b6d9c463 [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
Stephan Pleinesf63bde82024-01-13 15:59:33 -08006namespace frc971::controls {
milind-ue53bf552021-12-11 14:42:00 -08007namespace {
Brian Silvermandac0a4b2020-06-23 17:03:09 -07008
milind-ue53bf552021-12-11 14:42:00 -08009double SinXoverX(double x) {
10 const double xsquared = x * x;
Brian Silvermandac0a4b2020-06-23 17:03:09 -070011
12 // sin(x)/x = 1
13 double sinx_x = 1.0;
14
15 // - x^2/3!
milind-ue53bf552021-12-11 14:42:00 -080016 double value = xsquared / 6.0;
Brian Silvermandac0a4b2020-06-23 17:03:09 -070017 sinx_x -= value;
18
19 // + x^4/5!
milind-ue53bf552021-12-11 14:42:00 -080020 value = value * xsquared / 20.0;
Brian Silvermandac0a4b2020-06-23 17:03:09 -070021 sinx_x += value;
22
23 // - x^6/7!
milind-ue53bf552021-12-11 14:42:00 -080024 value = value * xsquared / (6.0 * 7.0);
Brian Silvermandac0a4b2020-06-23 17:03:09 -070025 sinx_x -= value;
26
27 // + x^8/9!
milind-ue53bf552021-12-11 14:42:00 -080028 value = value * xsquared / (8.0 * 9.0);
Brian Silvermandac0a4b2020-06-23 17:03:09 -070029 sinx_x += value;
30
31 // - x^10/11!
milind-ue53bf552021-12-11 14:42:00 -080032 value = value * xsquared / (10.0 * 11.0);
Brian Silvermandac0a4b2020-06-23 17:03:09 -070033 sinx_x -= value;
34
35 // + x^12/13!
milind-ue53bf552021-12-11 14:42:00 -080036 value = value * xsquared / (12.0 * 13.0);
Brian Silvermandac0a4b2020-06-23 17:03:09 -070037 sinx_x += value;
38
39 // - x^14/15!
milind-ue53bf552021-12-11 14:42:00 -080040 value = value * xsquared / (14.0 * 15.0);
Brian Silvermandac0a4b2020-06-23 17:03:09 -070041 sinx_x -= value;
42
43 // + x^16/17!
milind-ue53bf552021-12-11 14:42:00 -080044 value = value * xsquared / (16.0 * 17.0);
Brian Silvermandac0a4b2020-06-23 17:03:09 -070045 sinx_x += value;
46
milind-ue53bf552021-12-11 14:42:00 -080047 return sinx_x;
48
Brian Silvermandac0a4b2020-06-23 17:03:09 -070049 // To plot the residual in matplotlib, run:
50 // import numpy
51 // import scipy
52 // from matplotlib import pyplot
53 // x = numpy.arange(-numpy.pi, numpy.pi, 0.01)
54 // pyplot.plot(x, 1 - x**2 / scipy.misc.factorial(3) +
55 // x**4 / scipy.misc.factorial(5) -
56 // x**6 / scipy.misc.factorial(7) +
57 // x**8 / scipy.misc.factorial(9) -
58 // x ** 10 / scipy.misc.factorial(11) +
59 // x ** 12 / scipy.misc.factorial(13) -
60 // x ** 14 / scipy.misc.factorial(15) +
61 // x ** 16 / scipy.misc.factorial(17) -
62 // numpy.sin(x) / x)
Brian Silvermandac0a4b2020-06-23 17:03:09 -070063}
64
milind-ue53bf552021-12-11 14:42:00 -080065} // namespace
66
Brian Silvermandac0a4b2020-06-23 17:03:09 -070067inline Eigen::Matrix<double, 4, 1> MaybeFlipX(
68 const Eigen::Matrix<double, 4, 1> &X) {
69 if (X(3, 0) < 0.0) {
70 return -X;
71 } else {
72 return X;
73 }
74}
75
milind-ue53bf552021-12-11 14:42:00 -080076Eigen::Matrix<double, 4, 1> ToQuaternionFromRotationVector(
77 const Eigen::Matrix<double, 3, 1> &X, const double max_angle_cap) {
78 const double unclipped_angle = X.norm();
79 const double angle_scalar =
80 (unclipped_angle > max_angle_cap) ? max_angle_cap / unclipped_angle : 1.0;
81 const double angle = unclipped_angle * angle_scalar;
82 const double half_angle = angle * 0.5;
83
84 const double scalar = SinXoverX(half_angle) * 0.5;
85
86 Eigen::Matrix<double, 4, 1> result;
87 result.block<3, 1>(0, 0) = X * scalar * angle_scalar;
88 result(3, 0) = std::cos(half_angle);
89 return result;
90}
91
92// q = cos(a/2) + i ( x * sin(a/2)) + j (y * sin(a/2)) + k ( z * sin(a/2))
93
Brian Silvermandac0a4b2020-06-23 17:03:09 -070094Eigen::Matrix<double, 3, 1> ToRotationVectorFromQuaternion(
95 const Eigen::Matrix<double, 4, 1> &X) {
96 // TODO(austin): Verify we still need it.
97 const Eigen::Matrix<double, 4, 1> corrected_X = MaybeFlipX(X);
98 const double half_angle =
99 std::atan2(corrected_X.block<3, 1>(0, 0).norm(), corrected_X(3, 0));
100
milind-ue53bf552021-12-11 14:42:00 -0800101 const double scalar = 2.0 / SinXoverX(half_angle);
Brian Silvermandac0a4b2020-06-23 17:03:09 -0700102
103 return corrected_X.block<3, 1>(0, 0) * scalar;
104}
105
milind-ue53bf552021-12-11 14:42:00 -0800106Eigen::Matrix<double, 4, 3> QuaternionDerivativeDerivitive(
107 const Eigen::Vector4d &q_matrix) {
108 // qa * qb = (a.w() * b.x() + a.x() * b.w() + a.y() * b.z() - a.z() * b.y(),
109 // a.w() * b.y() + a.y() * b.w() + a.z() * b.x() - a.x() * b.z(),
110 // a.w() * b.z() + a.z() * b.w() + a.x() * b.y() - a.y() * b.x(),
111 // a.w() * b.w() - a.x() * b.x() - a.y() * b.y() - a.z() * b.z())
112 //
113 // We want q * omega_q = result * omega.
114 Eigen::Matrix<double, 4, 3> result;
115 result(3, 0) = -q_matrix.x() * 0.5;
116 result(3, 1) = -q_matrix.y() * 0.5;
117 result(3, 2) = -q_matrix.z() * 0.5;
118
119 result(0, 0) = q_matrix.w() * 0.5;
120 result(0, 1) = -q_matrix.z() * 0.5;
121 result(0, 2) = q_matrix.y() * 0.5;
122
123 result(1, 0) = q_matrix.z() * 0.5;
124 result(1, 1) = q_matrix.w() * 0.5;
125 result(1, 2) = -q_matrix.x() * 0.5;
126
127 result(2, 0) = -q_matrix.y() * 0.5;
128 result(2, 1) = q_matrix.x() * 0.5;
129 result(2, 2) = q_matrix.w() * 0.5;
130
131 return result;
132}
133
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800134} // namespace frc971::controls