blob: adc183917f0fd7a832ec05f88101188220824af1 [file] [log] [blame]
Brian Silvermand9566392018-06-10 15:02:03 -07001#include "motors/fet12/motor_controls.h"
2
3#include "motors/peripheral/configuration.h"
4
Stephan Pleinesf63bde82024-01-13 15:59:33 -08005namespace frc971::motors {
Brian Silvermand9566392018-06-10 15:02:03 -07006namespace {
7
8template <int kRows, int kCols>
9using ComplexMatrix = MotorControlsImplementation::ComplexMatrix<kRows, kCols>;
10
11using Complex = ::std::complex<float>;
12
13constexpr int kCountsPerRevolution =
14 MotorControlsImplementation::constant_counts_per_revolution();
15
16#if 1
17constexpr double kMaxDutyCycle = 0.98;
18#elif 1
19constexpr double kMaxDutyCycle = 0.6;
20#elif 0
21constexpr double kMaxDutyCycle = 0.2;
22#endif
23
24constexpr int kPhaseBOffset = kCountsPerRevolution / 3;
25constexpr int kPhaseCOffset = 2 * kCountsPerRevolution / 3;
26
James Kuszmaul998d3032018-09-08 15:41:41 -070027constexpr double K1_unscaled = 1.0;
28constexpr double K2_unscaled = 1.0 / -6.4786;
Brian Silvermand9566392018-06-10 15:02:03 -070029
30// Make the amplitude of the fundamental 1 for ease of math.
31constexpr double K2 = K2_unscaled / K1_unscaled;
James Kuszmaul998d3032018-09-08 15:41:41 -070032constexpr double K1 = 1.0;
Brian Silvermand9566392018-06-10 15:02:03 -070033
34// volts
James Kuszmaul998d3032018-09-08 15:41:41 -070035constexpr double kVcc = 31.5;
Brian Silvermand9566392018-06-10 15:02:03 -070036
James Kuszmaul521eb652018-10-17 19:09:33 -070037// 3.6 and 1.15 are adjustments from calibrations.
38constexpr double Kv = 22000.0 * 2.0 * M_PI / 60.0 / 30.0 * 3.6 * 1.15;
Brian Silvermand9566392018-06-10 15:02:03 -070039
Brian Silverman37a95d62018-11-09 16:08:32 -080040constexpr double kL = 5e-06;
James Kuszmaul998d3032018-09-08 15:41:41 -070041constexpr double kM = 0;
Brian Silverman37a95d62018-11-09 16:08:32 -080042constexpr double kR = 0.0079;
43constexpr float kAdiscrete_diagonal = 0.92404f;
James Kuszmaul998d3032018-09-08 15:41:41 -070044constexpr float kAdiscrete_offdiagonal = 0.0f;
Brian Silverman37a95d62018-11-09 16:08:32 -080045constexpr float kBdiscrete_inv_diagonal = 0.104002f;
James Kuszmaul998d3032018-09-08 15:41:41 -070046constexpr float kBdiscrete_inv_offdiagonal = 0.0f;
James Kuszmaul521eb652018-10-17 19:09:33 -070047constexpr double kOneAmpScalar = 1.46785;
Brian Silverman37a95d62018-11-09 16:08:32 -080048constexpr double kMaxOneAmpDrivingVoltage = 0.0434948;
Brian Silvermand9566392018-06-10 15:02:03 -070049
50::Eigen::Matrix<float, 3, 3> A_discrete() {
51 ::Eigen::Matrix<float, 3, 3> r;
James Kuszmaul998d3032018-09-08 15:41:41 -070052 r << kAdiscrete_diagonal, kAdiscrete_offdiagonal, kAdiscrete_offdiagonal,
53 kAdiscrete_offdiagonal, kAdiscrete_diagonal, kAdiscrete_offdiagonal,
54 kAdiscrete_offdiagonal, kAdiscrete_offdiagonal, kAdiscrete_diagonal;
Brian Silvermand9566392018-06-10 15:02:03 -070055 return r;
56}
57
58::Eigen::Matrix<float, 3, 3> B_discrete_inverse() {
James Kuszmaul998d3032018-09-08 15:41:41 -070059 return ::Eigen::Matrix<float, 1, 3>::Constant(kBdiscrete_inv_diagonal)
60 .asDiagonal();
Brian Silvermand9566392018-06-10 15:02:03 -070061}
62
Brian Silvermand9566392018-06-10 15:02:03 -070063// Use FluxLinkageTable() to access this with a const so you don't accidentally
64// modify it.
65float flux_linkage_table[kCountsPerRevolution];
66
67void MakeFluxLinkageTable() {
68 for (int i = 0; i < kCountsPerRevolution; ++i) {
69 const double theta = static_cast<double>(i) /
70 static_cast<double>(kCountsPerRevolution) * 2.0 * M_PI;
71 flux_linkage_table[i] = K1 * sin(theta) - K2 * sin(theta * 5);
72 }
73}
74
75// theta doesn't have to be less than kCountsPerRevolution.
76::Eigen::Matrix<float, 3, 1> FluxLinkageAt(uint32_t theta) {
77 ::Eigen::Matrix<float, 3, 1> r;
78 r(0) = flux_linkage_table[theta % kCountsPerRevolution];
79 r(1) = flux_linkage_table[(theta + kPhaseBOffset) % kCountsPerRevolution];
80 r(2) = flux_linkage_table[(theta + kPhaseCOffset) % kCountsPerRevolution];
81 return r;
82}
83
84::Eigen::Matrix<float, 3, 3> MakeK() {
85 ::Eigen::Matrix<float, 3, 3> Vconv;
86 Vconv << 2.0f, -1.0f, -1.0f, -1.0f, 2.0f, -1.0f, -1.0f, -1.0f, 2.0f;
James Kuszmaul998d3032018-09-08 15:41:41 -070087 static constexpr float kControllerGain = 0.05f;
Brian Silvermand9566392018-06-10 15:02:03 -070088 return kControllerGain * (Vconv / 3.0f);
89}
90
91ComplexMatrix<3, 1> MakeE1Unrotated() {
92 ComplexMatrix<3, 1> rotation;
93 rotation << Complex(0, -1), Complex(::std::sqrt(3) / 2, 0.5),
94 Complex(-::std::sqrt(3) / 2, 0.5);
95 return K1 * rotation;
96}
97
98ComplexMatrix<3, 1> MakeE2Unrotated() {
99 ComplexMatrix<3, 1> rotation;
100 rotation << Complex(0, -1), Complex(-::std::sqrt(3) / 2, 0.5),
101 Complex(::std::sqrt(3) / 2, 0.5);
102 return K2 * rotation;
103}
104
105ComplexMatrix<3, 3> Hn(float omega, int scalar) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700106 const Complex a(static_cast<float>(kR),
107 omega * static_cast<float>(scalar * kL));
108 const Complex b(0, omega * static_cast<float>(scalar * kM));
Brian Silvermand9566392018-06-10 15:02:03 -0700109 const Complex temp1 = a + b;
110 const Complex temp2 = -b;
111 ComplexMatrix<3, 3> matrix;
112 matrix << temp1, temp2, temp2, temp2, temp1, temp2, temp2, temp2, temp1;
113 return matrix *
114 -(omega / static_cast<float>(Kv) / (a * a + a * b - 2.0f * b * b));
115}
116
117} // namespace
118
119MotorControlsImplementation::MotorControlsImplementation()
120 : E1Unrotated_(MakeE1Unrotated()), E2Unrotated_(MakeE2Unrotated()) {
121 MakeFluxLinkageTable();
122}
123
James Kuszmaul998d3032018-09-08 15:41:41 -0700124::std::array<float, 3> MotorControlsImplementation::DoIteration(
Brian Silvermand9566392018-06-10 15:02:03 -0700125 const float raw_currents[3], const uint32_t theta_in,
126 const float command_current) {
James Kuszmaul998d3032018-09-08 15:41:41 -0700127 static constexpr float kCurrentSlewRate = 0.10f;
Brian Silvermand9566392018-06-10 15:02:03 -0700128 if (command_current > filtered_current_ + kCurrentSlewRate) {
129 filtered_current_ += kCurrentSlewRate;
130 } else if (command_current < filtered_current_ - kCurrentSlewRate) {
131 filtered_current_ -= kCurrentSlewRate;
132 } else {
133 filtered_current_ = command_current;
134 }
135 const float goal_current_in = filtered_current_;
136 const float max_current =
James Kuszmaul998d3032018-09-08 15:41:41 -0700137 (static_cast<float>(kVcc * kMaxDutyCycle) -
Brian Silvermand9566392018-06-10 15:02:03 -0700138 estimated_velocity_ / static_cast<float>(Kv / 2.0)) /
139 static_cast<float>(kMaxOneAmpDrivingVoltage);
140 const float min_current =
James Kuszmaul998d3032018-09-08 15:41:41 -0700141 (-static_cast<float>(kVcc * kMaxDutyCycle) -
Brian Silvermand9566392018-06-10 15:02:03 -0700142 estimated_velocity_ / static_cast<float>(Kv / 2.0)) /
143 static_cast<float>(kMaxOneAmpDrivingVoltage);
144 const float goal_current =
145 ::std::max(min_current, ::std::min(max_current, goal_current_in));
146
147#if 0
148 const uint32_t theta =
149 (theta_in + static_cast<uint32_t>(estimated_velocity_ * 1.0f)) % 1024;
150#elif 0
151 const uint32_t theta =
152 (theta_in + kCountsPerRevolution - 160u) % kCountsPerRevolution;
James Kuszmaul998d3032018-09-08 15:41:41 -0700153#elif 0
Brian Silvermand9566392018-06-10 15:02:03 -0700154 const uint32_t theta =
155 (theta_in + kCountsPerRevolution +
156 ((estimated_velocity_ > 0) ? (kCountsPerRevolution - 10u) : 60u)) %
157 kCountsPerRevolution;
James Kuszmaul998d3032018-09-08 15:41:41 -0700158#elif 1
Brian Silvermand9566392018-06-10 15:02:03 -0700159 const uint32_t theta = theta_in;
160#endif
161
162 const ::Eigen::Matrix<float, 3, 1> measured_current =
163 (::Eigen::Matrix<float, 3, 1>() << scale_current_reading(raw_currents[0]),
164 scale_current_reading(raw_currents[1]),
Philipp Schrader790cb542023-07-05 21:06:52 -0700165 scale_current_reading(raw_currents[2]))
166 .finished();
Brian Silvermand9566392018-06-10 15:02:03 -0700167
168 const ComplexMatrix<3, 1> E1 =
169 E1Unrotated_ *
170 ImaginaryExpInt<::std::ratio<1, constant_counts_per_revolution()>>(theta);
171 const ComplexMatrix<3, 1> E2 =
172 E2Unrotated_ *
173 ImaginaryExpInt<::std::ratio<5, constant_counts_per_revolution()>>(theta);
174
175 const float overall_measured_current =
176 ((E1 + E2).real().transpose() * measured_current /
177 static_cast<float>(kOneAmpScalar))(0);
James Kuszmaul521eb652018-10-17 19:09:33 -0700178 overall_measured_current_ = overall_measured_current;
Brian Silvermand9566392018-06-10 15:02:03 -0700179 const float current_error = goal_current - overall_measured_current;
180 estimated_velocity_ += current_error * 0.1f;
181 debug_[3] = theta;
182 const float omega = estimated_velocity_;
183
184 debug_[4] = max_current * 10;
185
186 const ::Eigen::Matrix<float, 3, 1> I_now = I_last_;
187 const ::Eigen::Matrix<float, 3, 1> I_next =
James Kuszmaul998d3032018-09-08 15:41:41 -0700188 FluxLinkageAt(theta +
189 static_cast<int32_t>(
190 2.0f * omega * kCountsPerRevolution /
191 static_cast<float>(2.0 * M_PI * SWITCHING_FREQUENCY))) *
192 goal_current;
Brian Silvermand9566392018-06-10 15:02:03 -0700193
194 const ComplexMatrix<3, 3> H1 = Hn(omega, 1);
195 const ComplexMatrix<3, 3> H2 = Hn(omega, 5);
196
James Kuszmaul998d3032018-09-08 15:41:41 -0700197 const ::std::complex<float> first_speed_delay =
198 ImaginaryExpFloat(omega / SWITCHING_FREQUENCY);
199 const ::std::complex<float> fifth_speed_delay =
200 ImaginaryExpFloat(omega * 5.0f / SWITCHING_FREQUENCY);
201 const ComplexMatrix<3, 1> H1E1 = first_speed_delay * H1 * E1;
202 const ComplexMatrix<3, 1> H2E2 = fifth_speed_delay * H2 * E2;
Brian Silvermand9566392018-06-10 15:02:03 -0700203 const ComplexMatrix<3, 1> p_imaginary = H1E1 + H2E2;
204 const ComplexMatrix<3, 1> p_next_imaginary =
James Kuszmaul998d3032018-09-08 15:41:41 -0700205 first_speed_delay * H1E1 + fifth_speed_delay * H2E2;
Brian Silvermand9566392018-06-10 15:02:03 -0700206 const ::Eigen::Matrix<float, 3, 1> p = p_imaginary.real();
207 const ::Eigen::Matrix<float, 3, 1> p_next = p_next_imaginary.real();
208
209 const ::Eigen::Matrix<float, 3, 1> Vn_ff =
210 B_discrete_inverse() * (I_next - A_discrete() * (I_now - p) - p_next);
211 const ::Eigen::Matrix<float, 3, 1> Vn =
James Kuszmaul521eb652018-10-17 19:09:33 -0700212 Vn_ff + MakeK() * (I_prev_ - measured_current);
Brian Silvermand9566392018-06-10 15:02:03 -0700213
214 debug_[0] = (I_next)(0) * 100;
215 debug_[1] = (I_next)(1) * 100;
216 debug_[2] = (I_next)(2) * 100;
217
218 debug_[5] = Vn(0) * 100;
219 debug_[6] = Vn(1) * 100;
220 debug_[7] = Vn(2) * 100;
221
James Kuszmaul998d3032018-09-08 15:41:41 -0700222 ::Eigen::Matrix<float, 3, 1> times = Vn / kVcc;
Brian Silvermand9566392018-06-10 15:02:03 -0700223 {
224 const float min_time = times.minCoeff();
225 times -= ::Eigen::Matrix<float, 3, 1>::Constant(min_time);
226 }
227 {
228 const float max_time = times.maxCoeff();
229 const float scalar =
230 static_cast<float>(kMaxDutyCycle) /
231 ::std::max(static_cast<float>(kMaxDutyCycle), max_time);
232 times *= scalar;
233 }
234
James Kuszmaul521eb652018-10-17 19:09:33 -0700235 I_prev_ = I_now;
Brian Silvermand9566392018-06-10 15:02:03 -0700236 I_last_ = I_next;
237
238 // TODO(Austin): Figure out why we need the min here.
James Kuszmaul998d3032018-09-08 15:41:41 -0700239 return {::std::max(0.0f, times(0)), ::std::max(0.0f, times(1)),
240 ::std::max(0.0f, times(2))};
Brian Silvermand9566392018-06-10 15:02:03 -0700241}
242
243int16_t MotorControlsImplementation::Debug(uint32_t theta) {
244 return debug_[theta];
245}
246
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800247} // namespace frc971::motors