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