blob: c166a1344ff346510bab58d75b40d9f4afcd3ed0 [file] [log] [blame]
Brian Silvermanf4937f62013-10-16 10:32:00 -07001#include <string.h>
2
Brian Silverman2e0dcfd2013-03-30 22:44:40 -07003#include <memory>
4
5#include "aos/common/inttypes.h"
6#include "aos/atom_code/init.h"
7#include "aos/common/logging/logging.h"
8#include "aos/common/time.h"
Brian Silverman93871ee2013-09-14 18:15:28 -07009#include "aos/common/glibusb/glibusb.h"
10#include "aos/common/glibusb/gbuffer.h"
Brian Silvermanf4937f62013-10-16 10:32:00 -070011#include "aos/common/util/wrapping_counter.h"
12#include "aos/common/control_loop/ControlLoop.h"
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070013
14#include "frc971/control_loops/drivetrain/drivetrain.q.h"
15#include "frc971/control_loops/wrist/wrist_motor.q.h"
16#include "frc971/control_loops/angle_adjust/angle_adjust_motor.q.h"
17#include "frc971/control_loops/index/index_motor.q.h"
18#include "frc971/control_loops/shooter/shooter_motor.q.h"
19#include "frc971/input/gyro_board_data.h"
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070020#include "frc971/queues/GyroAngle.q.h"
21
22#ifndef M_PI
23#define M_PI 3.14159265358979323846
24#endif
25
26using ::frc971::control_loops::drivetrain;
27using ::frc971::control_loops::wrist;
28using ::frc971::control_loops::angle_adjust;
29using ::frc971::control_loops::shooter;
30using ::frc971::control_loops::index_loop;
31using ::frc971::sensors::gyro;
Brian Silvermanf4937f62013-10-16 10:32:00 -070032using ::aos::util::WrappingCounter;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070033
34namespace frc971 {
35namespace {
36
37inline double drivetrain_translate(int32_t in) {
38 return static_cast<double>(in) / (256.0 /*cpr*/ * 4.0 /*quad*/) *
39 (19.0 / 50.0) /*output reduction*/ * (64.0 / 24.0) /*encoder gears*/ *
40 (3.5 /*wheel diameter*/ * 2.54 / 100.0 * M_PI);
41}
42
43inline double wrist_translate(int32_t in) {
44 return static_cast<double>(in) / (256.0 /*cpr*/ * 4.0 /*quad*/) *
45 (14.0 / 50.0 * 20.0 / 84.0) /*gears*/ * (2 * M_PI);
46}
47
48inline double angle_adjust_translate(int32_t in) {
49 static const double kCableDiameter = 0.060;
50 return -static_cast<double>(in) / (256.0 /*cpr*/ * 4.0 /*quad*/) *
51 ((0.75 + kCableDiameter) / (16.61125 + kCableDiameter)) /*pulleys*/ *
52 (2 * M_PI);
53}
54
55inline double shooter_translate(int32_t in) {
56 return static_cast<double>(in) / (32.0 /*cpr*/ * 4.0 /*quad*/) *
57 (15.0 / 34.0) /*gears*/ * (2 * M_PI);
58}
59
60inline double index_translate(int32_t in) {
61 return -static_cast<double>(in) / (128.0 /*cpr*/ * 4.0 /*quad*/) *
62 (1.0) /*gears*/ * (2 * M_PI);
63}
64
65} // namespace
66
Brian Silvermanf4937f62013-10-16 10:32:00 -070067class GyroSensorReceiver {
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070068 public:
Brian Silvermanf4937f62013-10-16 10:32:00 -070069 GyroSensorReceiver() {
70 Reset();
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070071 }
72
Brian Silvermanf4937f62013-10-16 10:32:00 -070073 void RunIteration() {
74 if (ReceiveData()) {
75 Reset();
Brian Silvermanf92396c2013-09-12 20:13:13 -070076 } else {
Brian Silvermanf4937f62013-10-16 10:32:00 -070077 const ::aos::time::Time received_time = ::aos::time::Time::Now();
78 if (phase_locker_.IsCurrentPacketGood(received_time, sequence_.count())) {
79 ProcessData();
80 }
Brian Silvermanf92396c2013-09-12 20:13:13 -070081 }
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070082 }
83
84 private:
Brian Silvermanf4937f62013-10-16 10:32:00 -070085 static const unsigned char kEndpoint = 0x83;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070086 // 0 is unlimited
Brian Silvermanf4937f62013-10-16 10:32:00 -070087 static constexpr ::aos::time::Time kReadTimeout =
88 ::aos::time::Time::InSeconds(1.5);
89 static constexpr ::glibusb::VendorProductId kDeviceId =
90 ::glibusb::VendorProductId(0x1424 /* vendor ID */,
91 0xd243 /* product ID */);
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070092
Brian Silvermanf4937f62013-10-16 10:32:00 -070093 static const int kPacketsPerLoopCycle = 10;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070094
Brian Silvermanf4937f62013-10-16 10:32:00 -070095 // Contains all of the complicated state and logic for locking onto the the
96 // correct phase.
97 class {
98 public:
99 void Reset() {
100 last_guessed_time_ = ::aos::time::Time(0, 0);
101 good_phase_ = guess_phase_ = kUnknownPhase;
102 guess_phase_good_ = guess_phase_bad_ = 0;
103 good_phase_early_ = good_phase_late_ = 0;
104 }
Brian Silverman9a574d52013-03-31 00:53:53 -0700105
Brian Silvermanf4937f62013-10-16 10:32:00 -0700106 // Gets called for every packet received.
107 // Returns whether or not to process the values from this packet.
108 bool IsCurrentPacketGood(const ::aos::time::Time &received_time,
109 int32_t sequence) {
110 // How often we (should) receive packets.
111 static const ::aos::time::Time kPacketFrequency =
112 ::aos::control_loops::kLoopFrequency / kPacketsPerLoopCycle;
113
114 // When we want to receive a packet for the next cycle of control loops.
115 const ::aos::time::Time next_desired =
116 ::aos::control_loops::NextLoopTime(received_time + kDesiredOffset);
117 // How far off of when we want the next packet this one is.
118 const ::aos::time::Time offset = next_desired - received_time;
119
120 const int received_phase = sequence % kPacketsPerLoopCycle;
121
122 assert(!(good_phase_early_ != 0 && good_phase_late_ != 0));
123
124 if (guess_phase_good_ > kMinGoodGuessCycles) {
125 good_phase_ = guess_phase_;
126 if (guess_phase_offset_ < kPacketFrequency * -0.5) {
127 ++good_phase_;
128 } else if (guess_phase_offset_ > kPacketFrequency * 0.5) {
129 --good_phase_;
130 }
131 } else if (guess_phase_bad_ > kMaxBadGuessCycles) {
132 Reset();
133 }
134 if (good_phase_early_ > kSwitchCycles) {
135 good_phase_early_ = 0;
136 --good_phase_;
137 } else if (good_phase_late_ > kSwitchCycles) {
138 good_phase_late_ = 0;
139 ++good_phase_;
140 }
141 if (good_phase_ == kUnknownPhase) {
142 LOG(INFO, "guessing which packet is good\n");
143
144 // If we're going to call this packet a good guess.
145 bool guess_is_good = false;
146 // If it's close to the right time.
147 if (offset.abs() < kPacketFrequency * 0.65) {
148 // If we didn't (also) guess that the previous one was good.
149 if (received_time - last_guessed_time_ > kPacketFrequency * 2) {
150 guess_is_good = true;
151 }
152 if (guess_phase_ == kUnknownPhase) {
153 if (offset.abs() < kPacketFrequency * 0.55) {
154 guess_phase_ = received_phase;
155 guess_phase_offset_ = offset;
156 }
157 } else if (received_phase == guess_phase_) {
158 ++guess_phase_good_;
159 guess_phase_bad_ = 0;
160 guess_phase_offset_ = (guess_phase_offset_ * 9 + offset) / 10;
161 }
162 } else if (guess_phase_ != kUnknownPhase &&
163 received_phase == guess_phase_) {
164 ++guess_phase_bad_;
165 guess_phase_good_ = ::std::max(0, guess_phase_good_ -
166 (kMinGoodGuessCycles / 10));
167 }
168 if (guess_is_good) {
169 last_guessed_time_ = received_time;
170 return true;
171 } else {
172 return false;
173 }
174 } else { // we know what phase we're looking for
175 // Deal with it if the above logic for tweaking the phase that we're
176 // using wrapped it around.
177 if (good_phase_ == -1) {
178 good_phase_ = kPacketsPerLoopCycle;
179 } else if (good_phase_ == kPacketsPerLoopCycle) {
180 good_phase_ = 0;
181 }
182 assert(good_phase_ >= 0);
183 assert(good_phase_ < kPacketsPerLoopCycle);
184
185 if (received_phase == good_phase_) {
186 if (offset < kPacketFrequency * -0.6) {
187 ++good_phase_early_;
188 good_phase_late_ = 0;
189 } else if (offset > kPacketFrequency * 0.6) {
190 ++good_phase_late_;
191 good_phase_early_ = 0;
192 } else {
193 good_phase_early_ = good_phase_late_ = 0;
194 }
195 return true;
196 } else {
197 return false;
198 }
199 }
200 }
201
202 private:
203 // How long before the control loops run we want to use a packet.
204 static constexpr ::aos::time::Time kDesiredOffset =
205 ::aos::time::Time::InSeconds(-0.0025);
206
207 // How many times the packet we guessed has to be close to right to use the
208 // guess.
209 static const int kMinGoodGuessCycles = 30;
210 // How many times in a row we have to guess the wrong packet before trying
211 // again.
212 static const int kMaxBadGuessCycles = 3;
213
214 // How many times in a row a different packet has to be better than the one
215 // that we're using befor switching to it.
216 static const int kSwitchCycles = 15;
217
218 ::aos::time::Time last_guessed_time_{0, 0};
219
220 const int kUnknownPhase = -11;
221 // kUnknownPhase or the sequence number (%kPacketsPerLoopCycle) to
222 // use or think about using.
223 // If not kUnknownPhase, 0 <= these < kPacketsPerLoopCycle.
224 int good_phase_, guess_phase_;
225 int guess_phase_good_, guess_phase_bad_;
226 ::aos::time::Time guess_phase_offset_{0, 0};
227 int good_phase_early_, good_phase_late_;
228 } phase_locker_;
229
230 // Returns true if receiving failed and we should try a Reset().
231 bool ReceiveData() {
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700232 // Loop and then return once we get a good one.
233 while (true) {
Brian Silvermanf4937f62013-10-16 10:32:00 -0700234 using ::glibusb::UsbEndpoint;
Brian Silverman93871ee2013-09-14 18:15:28 -0700235 UsbEndpoint::IoStatus result =
236 endpoint_->ReadAtMostWithTimeout(sizeof(GyroBoardData),
Brian Silvermanf4937f62013-10-16 10:32:00 -0700237 kReadTimeout.ToMSec(),
Brian Silverman93871ee2013-09-14 18:15:28 -0700238 &buffer_);
239 switch (result) {
240 case UsbEndpoint::kSuccess:
241 break;
242 case UsbEndpoint::kTimeout:
243 LOG(WARNING, "read timed out\n");
Brian Silvermanf4937f62013-10-16 10:32:00 -0700244 return true;
Brian Silverman93871ee2013-09-14 18:15:28 -0700245 case UsbEndpoint::kNoDevice:
246 LOG(ERROR, "no device\n");
247 return true;
248 case UsbEndpoint::kUnknown:
249 case UsbEndpoint::kFail:
250 case UsbEndpoint::kAbort:
251 LOG(ERROR, "read failed\n");
252 continue;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700253 }
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700254 }
Brian Silvermanf4937f62013-10-16 10:32:00 -0700255 sequence_.Update(data()->sequence);
256 return false;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700257 }
258
Brian Silvermanf4937f62013-10-16 10:32:00 -0700259 GyroBoardData *data() {
260 return static_cast<GyroBoardData *>(
261 buffer_.GetBufferPointer(sizeof(GyroBoardData)));
262 }
263
264 void Reset() {
265 // Make sure to delete the endpoint before its device.
266 endpoint_.reset();
267 device_ = ::std::unique_ptr< ::glibusb::UsbDevice>(
Brian Silverman93871ee2013-09-14 18:15:28 -0700268 libusb_.FindSingleMatchingDeviceOrLose(kDeviceId));
269 CHECK(device_);
Brian Silvermanf4937f62013-10-16 10:32:00 -0700270 endpoint_ = ::std::unique_ptr< ::glibusb::UsbInEndpoint>(
Brian Silverman93871ee2013-09-14 18:15:28 -0700271 device_->InEndpoint(kEndpoint));
Brian Silvermanf4937f62013-10-16 10:32:00 -0700272 sequence_.Reset();
273 phase_locker_.Reset();
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700274 }
275
Brian Silvermanf4937f62013-10-16 10:32:00 -0700276 void ProcessData() {
277 if (data()->robot_id != 0) {
278 LOG(ERROR, "gyro board sent data for robot id %hhd!"
279 " dip switches are %x\n",
280 data()->robot_id, data()->base_status & 0xF);
281 return;
282 } else {
283 LOG(DEBUG, "processing a packet dip switches %x\n",
284 data()->base_status & 0xF);
285 }
286
287 static ::aos::time::Time last_time = ::aos::time::Time::Now();
288 if ((last_time - ::aos::time::Time::Now()) >
289 ::aos::time::Time::InMS(0.0011)) {
290 LOG(INFO, "missed one\n");
291 }
292
293 gyro.MakeWithBuilder()
294 .angle(data()->gyro_angle / 16.0 / 1000.0 / 180.0 * M_PI)
295 .Send();
296
297 drivetrain.position.MakeWithBuilder()
298 .right_encoder(drivetrain_translate(data()->main.right_drive))
299 .left_encoder(-drivetrain_translate(data()->main.left_drive))
300 .Send();
301
302 wrist.position.MakeWithBuilder()
303 .pos(wrist_translate(data()->main.wrist))
304 .hall_effect(!data()->main.wrist_hall_effect)
305 .calibration(wrist_translate(data()->main.capture_wrist_rise))
306 .Send();
307
308 angle_adjust.position.MakeWithBuilder()
309 .angle(angle_adjust_translate(data()->main.shooter_angle))
310 .bottom_hall_effect(!data()->main.angle_adjust_bottom_hall_effect)
311 .middle_hall_effect(false)
312 .bottom_calibration(angle_adjust_translate(
313 data()->main.capture_shooter_angle_rise))
314 .middle_calibration(angle_adjust_translate(
315 0))
316 .Send();
317
318 shooter.position.MakeWithBuilder()
319 .position(shooter_translate(data()->main.shooter))
320 .Send();
321
322 index_loop.position.MakeWithBuilder()
323 .index_position(index_translate(data()->main.indexer))
324 .top_disc_detect(!data()->main.top_disc)
325 .top_disc_posedge_count(top_rise_.Update(data()->main.top_rise_count))
326 .top_disc_posedge_position(
327 index_translate(data()->main.capture_top_rise))
328 .top_disc_negedge_count(top_fall_.Update(data()->main.top_fall_count))
329 .top_disc_negedge_position(
330 index_translate(data()->main.capture_top_fall))
331 .bottom_disc_detect(!data()->main.bottom_disc)
332 .bottom_disc_posedge_count(
333 bottom_rise_.Update(data()->main.bottom_rise_count))
334 .bottom_disc_negedge_count(
335 bottom_fall_.Update(data()->main.bottom_fall_count))
336 .bottom_disc_negedge_wait_position(index_translate(
337 data()->main.capture_bottom_fall_delay))
338 .bottom_disc_negedge_wait_count(
339 bottom_fall_delay_.Update(data()->main.bottom_fall_delay_count))
340 .loader_top(data()->main.loader_top)
341 .loader_bottom(data()->main.loader_bottom)
342 .Send();
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700343 }
344
Brian Silvermanf4937f62013-10-16 10:32:00 -0700345 ::std::unique_ptr< ::glibusb::UsbDevice> device_;
346 ::std::unique_ptr< ::glibusb::UsbInEndpoint> endpoint_;
347 ::glibusb::Buffer buffer_;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700348
Brian Silvermanf4937f62013-10-16 10:32:00 -0700349 WrappingCounter sequence_;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700350
Brian Silvermanf4937f62013-10-16 10:32:00 -0700351 ::glibusb::Libusb libusb_;
352
353 WrappingCounter top_rise_;
354 WrappingCounter top_fall_;
355 WrappingCounter bottom_rise_;
356 WrappingCounter bottom_fall_delay_;
357 WrappingCounter bottom_fall_;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700358};
Brian Silvermanf4937f62013-10-16 10:32:00 -0700359constexpr ::glibusb::VendorProductId GyroSensorReceiver::kDeviceId;
360constexpr ::aos::time::Time GyroSensorReceiver::kReadTimeout;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700361
362} // namespace frc971
363
364int main() {
365 ::aos::Init();
Brian Silvermanf4937f62013-10-16 10:32:00 -0700366 ::frc971::GyroSensorReceiver receiver;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700367 while (true) {
368 receiver.RunIteration();
369 }
370 ::aos::Cleanup();
371}