blob: 0fafaeb9992b345b8112dff97ae75932023bb31e [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())) {
Brian Silverman7643bbb2013-10-24 15:58:37 -070079 LOG(DEBUG, "processing data\n");
Brian Silvermanf4937f62013-10-16 10:32:00 -070080 ProcessData();
Brian Silverman7643bbb2013-10-24 15:58:37 -070081 } else {
82 LOG(DEBUG, "not processing\n");
Brian Silvermanf4937f62013-10-16 10:32:00 -070083 }
Brian Silvermanf92396c2013-09-12 20:13:13 -070084 }
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070085 }
86
87 private:
Brian Silverman7643bbb2013-10-24 15:58:37 -070088 static const unsigned char kEndpoint = 0x3;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070089 // 0 is unlimited
Brian Silvermanf4937f62013-10-16 10:32:00 -070090 static constexpr ::aos::time::Time kReadTimeout =
91 ::aos::time::Time::InSeconds(1.5);
92 static constexpr ::glibusb::VendorProductId kDeviceId =
93 ::glibusb::VendorProductId(0x1424 /* vendor ID */,
94 0xd243 /* product ID */);
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070095
Brian Silvermanf4937f62013-10-16 10:32:00 -070096 static const int kPacketsPerLoopCycle = 10;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -070097
Brian Silverman7643bbb2013-10-24 15:58:37 -070098 // How long before the control loops run we want to use a packet.
99 static constexpr ::aos::time::Time kDesiredOffset =
100 ::aos::time::Time::InSeconds(-0.0025);
101
Brian Silvermanf4937f62013-10-16 10:32:00 -0700102 // Contains all of the complicated state and logic for locking onto the the
103 // correct phase.
104 class {
105 public:
106 void Reset() {
Brian Silverman7643bbb2013-10-24 15:58:37 -0700107 LOG(INFO, "resetting\n");
Brian Silvermanf4937f62013-10-16 10:32:00 -0700108 last_guessed_time_ = ::aos::time::Time(0, 0);
109 good_phase_ = guess_phase_ = kUnknownPhase;
110 guess_phase_good_ = guess_phase_bad_ = 0;
111 good_phase_early_ = good_phase_late_ = 0;
112 }
Brian Silverman9a574d52013-03-31 00:53:53 -0700113
Brian Silvermanf4937f62013-10-16 10:32:00 -0700114 // Gets called for every packet received.
115 // Returns whether or not to process the values from this packet.
116 bool IsCurrentPacketGood(const ::aos::time::Time &received_time,
117 int32_t sequence) {
118 // How often we (should) receive packets.
119 static const ::aos::time::Time kPacketFrequency =
120 ::aos::control_loops::kLoopFrequency / kPacketsPerLoopCycle;
Brian Silverman7643bbb2013-10-24 15:58:37 -0700121 static const ::aos::time::Time kPacketClose =
122 kPacketFrequency * 65 / 100;
123 static const ::aos::time::Time kSwitchOffset =
124 kPacketFrequency * 6 / 10;
Brian Silvermanf4937f62013-10-16 10:32:00 -0700125
126 // When we want to receive a packet for the next cycle of control loops.
127 const ::aos::time::Time next_desired =
128 ::aos::control_loops::NextLoopTime(received_time + kDesiredOffset);
129 // How far off of when we want the next packet this one is.
130 const ::aos::time::Time offset = next_desired - received_time;
131
132 const int received_phase = sequence % kPacketsPerLoopCycle;
133
134 assert(!(good_phase_early_ != 0 && good_phase_late_ != 0));
135
136 if (guess_phase_good_ > kMinGoodGuessCycles) {
137 good_phase_ = guess_phase_;
Brian Silverman7643bbb2013-10-24 15:58:37 -0700138 if (guess_phase_offset_ < kPacketFrequency / -2) {
Brian Silvermanf4937f62013-10-16 10:32:00 -0700139 ++good_phase_;
Brian Silverman7643bbb2013-10-24 15:58:37 -0700140 } else if (guess_phase_offset_ > kPacketFrequency / 2) {
Brian Silvermanf4937f62013-10-16 10:32:00 -0700141 --good_phase_;
142 }
143 } else if (guess_phase_bad_ > kMaxBadGuessCycles) {
144 Reset();
145 }
146 if (good_phase_early_ > kSwitchCycles) {
147 good_phase_early_ = 0;
Brian Silverman7643bbb2013-10-24 15:58:37 -0700148 LOG(INFO, "switching to 1 phase earlier\n");
Brian Silvermanf4937f62013-10-16 10:32:00 -0700149 --good_phase_;
150 } else if (good_phase_late_ > kSwitchCycles) {
151 good_phase_late_ = 0;
Brian Silverman7643bbb2013-10-24 15:58:37 -0700152 LOG(INFO, "switching to 1 phase later\n");
Brian Silvermanf4937f62013-10-16 10:32:00 -0700153 ++good_phase_;
154 }
155 if (good_phase_ == kUnknownPhase) {
156 LOG(INFO, "guessing which packet is good\n");
157
158 // If we're going to call this packet a good guess.
159 bool guess_is_good = false;
160 // If it's close to the right time.
Brian Silverman7643bbb2013-10-24 15:58:37 -0700161 if (offset.abs() < kPacketClose) {
Brian Silvermanf4937f62013-10-16 10:32:00 -0700162 // If we didn't (also) guess that the previous one was good.
163 if (received_time - last_guessed_time_ > kPacketFrequency * 2) {
Brian Silverman7643bbb2013-10-24 15:58:37 -0700164 LOG(DEBUG, "guessing this one is good\n");
Brian Silvermanf4937f62013-10-16 10:32:00 -0700165 guess_is_good = true;
Brian Silverman7643bbb2013-10-24 15:58:37 -0700166 } else {
167 LOG(DEBUG, "just guessed\n");
Brian Silvermanf4937f62013-10-16 10:32:00 -0700168 }
169 if (guess_phase_ == kUnknownPhase) {
Brian Silverman7643bbb2013-10-24 15:58:37 -0700170 if (offset.abs() < kPacketFrequency * 55 / 100) {
Brian Silvermanf4937f62013-10-16 10:32:00 -0700171 guess_phase_ = received_phase;
172 guess_phase_offset_ = offset;
173 }
174 } else if (received_phase == guess_phase_) {
175 ++guess_phase_good_;
176 guess_phase_bad_ = 0;
177 guess_phase_offset_ = (guess_phase_offset_ * 9 + offset) / 10;
178 }
179 } else if (guess_phase_ != kUnknownPhase &&
180 received_phase == guess_phase_) {
181 ++guess_phase_bad_;
182 guess_phase_good_ = ::std::max(0, guess_phase_good_ -
183 (kMinGoodGuessCycles / 10));
184 }
185 if (guess_is_good) {
186 last_guessed_time_ = received_time;
187 return true;
188 } else {
189 return false;
190 }
191 } else { // we know what phase we're looking for
192 // Deal with it if the above logic for tweaking the phase that we're
193 // using wrapped it around.
194 if (good_phase_ == -1) {
195 good_phase_ = kPacketsPerLoopCycle;
196 } else if (good_phase_ == kPacketsPerLoopCycle) {
197 good_phase_ = 0;
198 }
199 assert(good_phase_ >= 0);
200 assert(good_phase_ < kPacketsPerLoopCycle);
201
202 if (received_phase == good_phase_) {
Brian Silverman7643bbb2013-10-24 15:58:37 -0700203 if (offset < -kSwitchOffset) {
Brian Silvermanf4937f62013-10-16 10:32:00 -0700204 ++good_phase_early_;
205 good_phase_late_ = 0;
Brian Silverman7643bbb2013-10-24 15:58:37 -0700206 } else if (offset > kSwitchOffset) {
Brian Silvermanf4937f62013-10-16 10:32:00 -0700207 ++good_phase_late_;
208 good_phase_early_ = 0;
209 } else {
210 good_phase_early_ = good_phase_late_ = 0;
211 }
212 return true;
213 } else {
214 return false;
215 }
216 }
217 }
218
219 private:
Brian Silvermanf4937f62013-10-16 10:32:00 -0700220 // How many times the packet we guessed has to be close to right to use the
221 // guess.
222 static const int kMinGoodGuessCycles = 30;
223 // How many times in a row we have to guess the wrong packet before trying
224 // again.
225 static const int kMaxBadGuessCycles = 3;
226
227 // How many times in a row a different packet has to be better than the one
228 // that we're using befor switching to it.
229 static const int kSwitchCycles = 15;
230
231 ::aos::time::Time last_guessed_time_{0, 0};
232
233 const int kUnknownPhase = -11;
234 // kUnknownPhase or the sequence number (%kPacketsPerLoopCycle) to
235 // use or think about using.
236 // If not kUnknownPhase, 0 <= these < kPacketsPerLoopCycle.
237 int good_phase_, guess_phase_;
238 int guess_phase_good_, guess_phase_bad_;
239 ::aos::time::Time guess_phase_offset_{0, 0};
240 int good_phase_early_, good_phase_late_;
241 } phase_locker_;
242
243 // Returns true if receiving failed and we should try a Reset().
244 bool ReceiveData() {
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700245 // Loop and then return once we get a good one.
246 while (true) {
Brian Silvermanf4937f62013-10-16 10:32:00 -0700247 using ::glibusb::UsbEndpoint;
Brian Silverman93871ee2013-09-14 18:15:28 -0700248 UsbEndpoint::IoStatus result =
249 endpoint_->ReadAtMostWithTimeout(sizeof(GyroBoardData),
Brian Silvermanf4937f62013-10-16 10:32:00 -0700250 kReadTimeout.ToMSec(),
Brian Silverman93871ee2013-09-14 18:15:28 -0700251 &buffer_);
252 switch (result) {
253 case UsbEndpoint::kSuccess:
Brian Silverman7643bbb2013-10-24 15:58:37 -0700254 sequence_.Update(data()->sequence);
255 return false;
Brian Silverman93871ee2013-09-14 18:15:28 -0700256 case UsbEndpoint::kTimeout:
257 LOG(WARNING, "read timed out\n");
Brian Silvermanf4937f62013-10-16 10:32:00 -0700258 return true;
Brian Silverman93871ee2013-09-14 18:15:28 -0700259 case UsbEndpoint::kNoDevice:
260 LOG(ERROR, "no device\n");
261 return true;
262 case UsbEndpoint::kUnknown:
263 case UsbEndpoint::kFail:
264 case UsbEndpoint::kAbort:
265 LOG(ERROR, "read failed\n");
266 continue;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700267 }
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700268 }
269 }
270
Brian Silvermanf4937f62013-10-16 10:32:00 -0700271 GyroBoardData *data() {
272 return static_cast<GyroBoardData *>(
273 buffer_.GetBufferPointer(sizeof(GyroBoardData)));
274 }
275
276 void Reset() {
277 // Make sure to delete the endpoint before its device.
278 endpoint_.reset();
279 device_ = ::std::unique_ptr< ::glibusb::UsbDevice>(
Brian Silverman93871ee2013-09-14 18:15:28 -0700280 libusb_.FindSingleMatchingDeviceOrLose(kDeviceId));
281 CHECK(device_);
Brian Silvermanf4937f62013-10-16 10:32:00 -0700282 endpoint_ = ::std::unique_ptr< ::glibusb::UsbInEndpoint>(
Brian Silverman93871ee2013-09-14 18:15:28 -0700283 device_->InEndpoint(kEndpoint));
Brian Silvermanf4937f62013-10-16 10:32:00 -0700284 sequence_.Reset();
285 phase_locker_.Reset();
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700286 }
287
Brian Silvermanf4937f62013-10-16 10:32:00 -0700288 void ProcessData() {
289 if (data()->robot_id != 0) {
290 LOG(ERROR, "gyro board sent data for robot id %hhd!"
291 " dip switches are %x\n",
292 data()->robot_id, data()->base_status & 0xF);
293 return;
294 } else {
295 LOG(DEBUG, "processing a packet dip switches %x\n",
296 data()->base_status & 0xF);
297 }
298
299 static ::aos::time::Time last_time = ::aos::time::Time::Now();
300 if ((last_time - ::aos::time::Time::Now()) >
301 ::aos::time::Time::InMS(0.0011)) {
302 LOG(INFO, "missed one\n");
303 }
304
305 gyro.MakeWithBuilder()
306 .angle(data()->gyro_angle / 16.0 / 1000.0 / 180.0 * M_PI)
307 .Send();
308
309 drivetrain.position.MakeWithBuilder()
310 .right_encoder(drivetrain_translate(data()->main.right_drive))
311 .left_encoder(-drivetrain_translate(data()->main.left_drive))
312 .Send();
313
314 wrist.position.MakeWithBuilder()
315 .pos(wrist_translate(data()->main.wrist))
316 .hall_effect(!data()->main.wrist_hall_effect)
317 .calibration(wrist_translate(data()->main.capture_wrist_rise))
318 .Send();
319
320 angle_adjust.position.MakeWithBuilder()
321 .angle(angle_adjust_translate(data()->main.shooter_angle))
322 .bottom_hall_effect(!data()->main.angle_adjust_bottom_hall_effect)
323 .middle_hall_effect(false)
324 .bottom_calibration(angle_adjust_translate(
325 data()->main.capture_shooter_angle_rise))
326 .middle_calibration(angle_adjust_translate(
327 0))
328 .Send();
329
330 shooter.position.MakeWithBuilder()
331 .position(shooter_translate(data()->main.shooter))
332 .Send();
333
334 index_loop.position.MakeWithBuilder()
335 .index_position(index_translate(data()->main.indexer))
336 .top_disc_detect(!data()->main.top_disc)
337 .top_disc_posedge_count(top_rise_.Update(data()->main.top_rise_count))
338 .top_disc_posedge_position(
339 index_translate(data()->main.capture_top_rise))
340 .top_disc_negedge_count(top_fall_.Update(data()->main.top_fall_count))
341 .top_disc_negedge_position(
342 index_translate(data()->main.capture_top_fall))
343 .bottom_disc_detect(!data()->main.bottom_disc)
344 .bottom_disc_posedge_count(
345 bottom_rise_.Update(data()->main.bottom_rise_count))
346 .bottom_disc_negedge_count(
347 bottom_fall_.Update(data()->main.bottom_fall_count))
348 .bottom_disc_negedge_wait_position(index_translate(
349 data()->main.capture_bottom_fall_delay))
350 .bottom_disc_negedge_wait_count(
351 bottom_fall_delay_.Update(data()->main.bottom_fall_delay_count))
352 .loader_top(data()->main.loader_top)
353 .loader_bottom(data()->main.loader_bottom)
354 .Send();
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700355 }
356
Brian Silvermanf4937f62013-10-16 10:32:00 -0700357 ::std::unique_ptr< ::glibusb::UsbDevice> device_;
358 ::std::unique_ptr< ::glibusb::UsbInEndpoint> endpoint_;
359 ::glibusb::Buffer buffer_;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700360
Brian Silvermanf4937f62013-10-16 10:32:00 -0700361 WrappingCounter sequence_;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700362
Brian Silvermanf4937f62013-10-16 10:32:00 -0700363 ::glibusb::Libusb libusb_;
364
365 WrappingCounter top_rise_;
366 WrappingCounter top_fall_;
367 WrappingCounter bottom_rise_;
368 WrappingCounter bottom_fall_delay_;
369 WrappingCounter bottom_fall_;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700370};
Brian Silvermanf4937f62013-10-16 10:32:00 -0700371constexpr ::glibusb::VendorProductId GyroSensorReceiver::kDeviceId;
372constexpr ::aos::time::Time GyroSensorReceiver::kReadTimeout;
Brian Silverman7643bbb2013-10-24 15:58:37 -0700373constexpr ::aos::time::Time GyroSensorReceiver::kDesiredOffset;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700374
375} // namespace frc971
376
377int main() {
378 ::aos::Init();
Brian Silvermanf4937f62013-10-16 10:32:00 -0700379 ::frc971::GyroSensorReceiver receiver;
Brian Silverman2e0dcfd2013-03-30 22:44:40 -0700380 while (true) {
381 receiver.RunIteration();
382 }
383 ::aos::Cleanup();
384}