blob: abc71e8b183d65bdd74e63d8eb8ce4c48eafde1a [file] [log] [blame]
Brian Silverman36d06492018-05-12 11:52:35 -07001#include "motors/big/motor_controls.h"
Brian Silverman8d3816a2017-07-03 18:52:15 -07002
3#include "motors/peripheral/configuration.h"
4
5namespace frc971 {
Brian Silvermana96c1a42018-05-12 12:11:31 -07006namespace motors {
Brian Silverman8d3816a2017-07-03 18:52:15 -07007namespace {
8
9template <int kRows, int kCols>
10using ComplexMatrix = MotorControlsImplementation::ComplexMatrix<kRows, kCols>;
11
12using Complex = ::std::complex<float>;
13
Brian Silverman19ea60f2018-01-03 21:43:15 -080014constexpr int kCountsPerRevolution =
15 MotorControlsImplementation::constant_counts_per_revolution();
Brian Silverman8d3816a2017-07-03 18:52:15 -070016
17#if 1
18constexpr double kMaxDutyCycle = 0.98;
19#elif 1
20constexpr double kMaxDutyCycle = 0.6;
21#elif 0
22constexpr double kMaxDutyCycle = 0.2;
23#endif
24
25constexpr int kPhaseBOffset = kCountsPerRevolution / 3;
26constexpr int kPhaseCOffset = 2 * kCountsPerRevolution / 3;
27
28constexpr double K1_unscaled = 1.81e04;
29constexpr double K2_unscaled = -2.65e03;
30
31// Make the amplitude of the fundamental 1 for ease of math.
32constexpr double K2 = K2_unscaled / K1_unscaled;
33constexpr double K1 = 1;
34
35// volts
36constexpr double vcc = 30.0;
37
38constexpr double Kv = 22000.0 * 2.0 * M_PI / 60.0 / 30.0 * 2.0;
39
40// Henries
41constexpr double L = 1e-05;
42
43constexpr double M = 1e-06;
44
45// ohms for system
46constexpr double R = 0.008;
47
48::Eigen::Matrix<float, 3, 3> A_discrete() {
49 ::Eigen::Matrix<float, 3, 3> r;
50 static constexpr float kDiagonal = 0.960091f;
51 static constexpr float kOffDiagonal = 0.00356245f;
52 r << kDiagonal, kOffDiagonal, kOffDiagonal, kOffDiagonal, kDiagonal,
53 kOffDiagonal, kOffDiagonal, kOffDiagonal, kDiagonal;
54 return r;
55}
56
57::Eigen::Matrix<float, 3, 3> B_discrete_inverse() {
58 return ::Eigen::Matrix<float, 1, 3>::Constant(0.18403f).asDiagonal();
59}
60
61// The number to divide the product of the unit BEMF and the per phase current
62// by to get motor current.
63constexpr double kOneAmpScalar = 1.46785;
64
65constexpr double kMaxOneAmpDrivingVoltage = 0.0361525;
66
67// Use FluxLinkageTable() to access this with a const so you don't accidentally
68// modify it.
69float flux_linkage_table[kCountsPerRevolution];
70
71void MakeFluxLinkageTable() {
72 for (int i = 0; i < kCountsPerRevolution; ++i) {
73 const double theta = static_cast<double>(i) /
74 static_cast<double>(kCountsPerRevolution) * 2.0 * M_PI;
75 flux_linkage_table[i] = K1 * sin(theta) - K2 * sin(theta * 5);
76 }
77}
78
79// theta doesn't have to be less than kCountsPerRevolution.
80::Eigen::Matrix<float, 3, 1> FluxLinkageAt(uint32_t theta) {
81 ::Eigen::Matrix<float, 3, 1> r;
82 r(0) = flux_linkage_table[theta % kCountsPerRevolution];
83 r(1) = flux_linkage_table[(theta + kPhaseBOffset) % kCountsPerRevolution];
84 r(2) = flux_linkage_table[(theta + kPhaseCOffset) % kCountsPerRevolution];
85 return r;
86}
87
88::Eigen::Matrix<float, 3, 3> MakeK() {
89 ::Eigen::Matrix<float, 3, 3> Vconv;
90 Vconv << 2.0f, -1.0f, -1.0f, -1.0f, 2.0f, -1.0f, -1.0f, -1.0f, 2.0f;
91 static constexpr float kControllerGain = 0.07f;
92 return kControllerGain * (Vconv / 3.0f);
93}
94
95ComplexMatrix<3, 1> MakeE1Unrotated() {
96 ComplexMatrix<3, 1> rotation;
97 rotation << Complex(0, -1), Complex(::std::sqrt(3) / 2, 0.5),
98 Complex(-::std::sqrt(3) / 2, 0.5);
99 return K1 * rotation;
100}
101
102ComplexMatrix<3, 1> MakeE2Unrotated() {
103 ComplexMatrix<3, 1> rotation;
104 rotation << Complex(0, -1), Complex(-::std::sqrt(3) / 2, 0.5),
105 Complex(::std::sqrt(3) / 2, 0.5);
106 return K2 * rotation;
107}
108
109ComplexMatrix<3, 3> Hn(float omega, int scalar) {
110 const Complex a(static_cast<float>(R),
111 omega * static_cast<float>(scalar * L));
112 const Complex b(0, omega * static_cast<float>(scalar * M));
113 const Complex temp1 = a + b;
114 const Complex temp2 = -b;
115 ComplexMatrix<3, 3> matrix;
116 matrix << temp1, temp2, temp2, temp2, temp1, temp2, temp2, temp2, temp1;
117 return matrix *
118 -(omega / static_cast<float>(Kv) / (a * a + a * b - 2.0f * b * b));
119}
120
121} // namespace
122
123MotorControlsImplementation::MotorControlsImplementation()
124 : E1Unrotated_(MakeE1Unrotated()), E2Unrotated_(MakeE2Unrotated()) {
125 MakeFluxLinkageTable();
126}
127
James Kuszmaul998d3032018-09-08 15:41:41 -0700128::std::array<float, 3> MotorControlsImplementation::DoIteration(
Brian Silverman8d3816a2017-07-03 18:52:15 -0700129 const float raw_currents[3], const uint32_t theta_in,
130 const float command_current) {
131 static constexpr float kCurrentSlewRate = 0.05f;
132 if (command_current > filtered_current_ + kCurrentSlewRate) {
133 filtered_current_ += kCurrentSlewRate;
134 } else if (command_current < filtered_current_ - kCurrentSlewRate) {
135 filtered_current_ -= kCurrentSlewRate;
136 } else {
137 filtered_current_ = command_current;
138 }
139 const float goal_current_in = filtered_current_;
140 const float max_current =
141 (static_cast<float>(vcc * kMaxDutyCycle) -
142 estimated_velocity_ / static_cast<float>(Kv / 2.0)) /
143 static_cast<float>(kMaxOneAmpDrivingVoltage);
144 const float min_current =
145 (-static_cast<float>(vcc * kMaxDutyCycle) -
146 estimated_velocity_ / static_cast<float>(Kv / 2.0)) /
147 static_cast<float>(kMaxOneAmpDrivingVoltage);
148 const float goal_current =
149 ::std::max(min_current, ::std::min(max_current, goal_current_in));
150
151#if 0
152 const uint32_t theta =
153 (theta_in + static_cast<uint32_t>(estimated_velocity_ * 1.0f)) % 1024;
154#elif 0
155 const uint32_t theta =
156 (theta_in + kCountsPerRevolution - 160u) % kCountsPerRevolution;
157#elif 1
158 const uint32_t theta =
159 (theta_in + kCountsPerRevolution +
160 ((estimated_velocity_ > 0) ? (kCountsPerRevolution - 10u) : 60u)) %
161 kCountsPerRevolution;
162#elif 0
163 const uint32_t theta = theta_in;
164#endif
165
166 const ::Eigen::Matrix<float, 3, 1> measured_current =
167 (::Eigen::Matrix<float, 3, 1>() << scale_current_reading(raw_currents[0]),
168 scale_current_reading(raw_currents[1]),
169 scale_current_reading(raw_currents[2])).finished();
170
171 const ComplexMatrix<3, 1> E1 =
172 E1Unrotated_ *
Brian Silverman19ea60f2018-01-03 21:43:15 -0800173 ImaginaryExpInt<::std::ratio<1, constant_counts_per_revolution()>>(theta);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700174 const ComplexMatrix<3, 1> E2 =
175 E2Unrotated_ *
Brian Silverman19ea60f2018-01-03 21:43:15 -0800176 ImaginaryExpInt<::std::ratio<5, constant_counts_per_revolution()>>(theta);
Brian Silverman8d3816a2017-07-03 18:52:15 -0700177
178 const float overall_measured_current =
179 ((E1 + E2).real().transpose() * measured_current /
180 static_cast<float>(kOneAmpScalar))(0);
James Kuszmaul521eb652018-10-17 19:09:33 -0700181 overall_measured_current_ = overall_measured_current;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700182 const float current_error = goal_current - overall_measured_current;
183 estimated_velocity_ += current_error * 0.1f;
184 debug_[3] = theta;
185 const float omega = estimated_velocity_;
186
187 debug_[4] = max_current * 10;
188
189 const ::Eigen::Matrix<float, 3, 1> I_now = I_last_;
190 const ::Eigen::Matrix<float, 3, 1> I_next =
191 FluxLinkageAt(theta) * goal_current;
192
193 const ComplexMatrix<3, 3> H1 = Hn(omega, 1);
194 const ComplexMatrix<3, 3> H2 = Hn(omega, 5);
195
Brian Silverman19ea60f2018-01-03 21:43:15 -0800196 const ComplexMatrix<3, 1> H1E1 = H1 * E1;
197 const ComplexMatrix<3, 1> H2E2 = H2 * E2;
198 const ComplexMatrix<3, 1> p_imaginary = H1E1 + H2E2;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700199 const ComplexMatrix<3, 1> p_next_imaginary =
Brian Silverman19ea60f2018-01-03 21:43:15 -0800200 ImaginaryExpFloat(omega / SWITCHING_FREQUENCY) * H1E1 +
201 ImaginaryExpFloat(omega * 5 / SWITCHING_FREQUENCY) * H2E2;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700202 const ::Eigen::Matrix<float, 3, 1> p = p_imaginary.real();
203 const ::Eigen::Matrix<float, 3, 1> p_next = p_next_imaginary.real();
204
205 const ::Eigen::Matrix<float, 3, 1> Vn_ff =
206 B_discrete_inverse() * (I_next - A_discrete() * (I_now - p) - p_next);
207 const ::Eigen::Matrix<float, 3, 1> Vn =
208 Vn_ff + MakeK() * (I_now - measured_current);
209
210 debug_[0] = (I_next)(0) * 100;
211 debug_[1] = (I_next)(1) * 100;
212 debug_[2] = (I_next)(2) * 100;
213
214 debug_[5] = Vn(0) * 100;
215 debug_[6] = Vn(1) * 100;
216 debug_[7] = Vn(2) * 100;
217
218 ::Eigen::Matrix<float, 3, 1> times = Vn / vcc;
219 {
220 const float min_time = times.minCoeff();
221 times -= ::Eigen::Matrix<float, 3, 1>::Constant(min_time);
222 }
223 {
224 const float max_time = times.maxCoeff();
225 const float scalar =
226 static_cast<float>(kMaxDutyCycle) /
227 ::std::max(static_cast<float>(kMaxDutyCycle), max_time);
228 times *= scalar;
229 }
230
231 I_last_ = I_next;
232
233 // TODO(Austin): Figure out why we need the min here.
James Kuszmaul998d3032018-09-08 15:41:41 -0700234 return {::std::max(0.0f, times(0)), ::std::max(0.0f, times(1)),
235 ::std::max(0.0f, times(2))};
Brian Silverman8d3816a2017-07-03 18:52:15 -0700236}
237
238int16_t MotorControlsImplementation::Debug(uint32_t theta) {
239 return debug_[theta];
240}
241
Brian Silvermana96c1a42018-05-12 12:11:31 -0700242} // namespace motors
Brian Silverman8d3816a2017-07-03 18:52:15 -0700243} // namespace frc971