blob: 554993a3fb2d1f12ff9354016314e6e36d78bcde [file] [log] [blame]
Austin Schuh010eb812014-10-25 18:06:49 -07001#include <stdio.h>
2#include <string.h>
Austin Schuh010eb812014-10-25 18:06:49 -07003#include <unistd.h>
4#include <inttypes.h>
5
Brian Silvermand8f403a2014-12-13 19:12:04 -05006#include <thread>
7#include <mutex>
8#include <functional>
9
Austin Schuh010eb812014-10-25 18:06:49 -070010#include "aos/common/controls/output_check.q.h"
11#include "aos/common/controls/sensor_generation.q.h"
12#include "aos/common/logging/logging.h"
13#include "aos/common/logging/queue_logging.h"
Brian Silvermand8f403a2014-12-13 19:12:04 -050014#include "aos/common/messages/robot_state.q.h"
Austin Schuh010eb812014-10-25 18:06:49 -070015#include "aos/common/time.h"
16#include "aos/common/util/log_interval.h"
17#include "aos/common/util/phased_loop.h"
18#include "aos/common/util/wrapping_counter.h"
Brian Silvermanb073f242014-09-08 16:29:57 -040019#include "aos/common/stl_mutex.h"
Austin Schuh010eb812014-10-25 18:06:49 -070020#include "aos/linux_code/init.h"
21
Brian Silverman335c20e2015-01-26 21:47:58 -050022#include "frc971/control_loops/control_loops.q.h"
Austin Schuh010eb812014-10-25 18:06:49 -070023#include "frc971/control_loops/drivetrain/drivetrain.q.h"
Daniel Pettiadf38432015-01-26 17:13:35 -080024#include "frc971/control_loops/fridge/fridge.q.h"
25#include "frc971/control_loops/claw/claw.q.h"
Austin Schuh010eb812014-10-25 18:06:49 -070026
Brian Silvermanda45b6c2014-12-28 11:36:50 -080027#include "frc971/wpilib/hall_effect.h"
28#include "frc971/wpilib/joystick_sender.h"
Brian Silvermand8f403a2014-12-13 19:12:04 -050029#include "frc971/wpilib/loop_output_handler.h"
30#include "frc971/wpilib/buffered_solenoid.h"
31#include "frc971/wpilib/buffered_pcm.h"
Brian Silverman07ec88e2014-12-28 00:13:08 -080032#include "frc971/wpilib/gyro_sender.h"
Brian Silvermanff7b3472015-01-26 17:53:04 -050033#include "frc971/wpilib/dma_edge_counting.h"
Brian Silverman70ec7192015-01-26 17:52:40 -050034#include "frc971/wpilib/interrupt_edge_counting.h"
Brian Silverman4da58072015-01-26 20:18:52 -050035#include "frc971/wpilib/encoder_and_potentiometer.h"
Brian Silvermanda45b6c2014-12-28 11:36:50 -080036
Brian Silvermancb77f232014-12-19 21:48:36 -080037#include "Encoder.h"
Brian Silvermancb77f232014-12-19 21:48:36 -080038#include "Talon.h"
39#include "DriverStation.h"
40#include "AnalogInput.h"
Brian Silvermancb77f232014-12-19 21:48:36 -080041#include "Compressor.h"
42#include "RobotBase.h"
Brian Silverman335c20e2015-01-26 21:47:58 -050043#include "dma.h"
Austin Schuh010eb812014-10-25 18:06:49 -070044
45#ifndef M_PI
46#define M_PI 3.14159265358979323846
47#endif
48
49using ::aos::util::SimpleLogInterval;
Brian Silvermanada5f2c2015-02-01 02:41:14 -050050using ::frc971::control_loops::drivetrain_queue;
Brian Silverman335c20e2015-01-26 21:47:58 -050051using ::frc971::control_loops::fridge_queue;
52using ::frc971::control_loops::claw_queue;
Austin Schuh010eb812014-10-25 18:06:49 -070053
54namespace frc971 {
Brian Silvermanda45b6c2014-12-28 11:36:50 -080055namespace wpilib {
Austin Schuh010eb812014-10-25 18:06:49 -070056
Austin Schuh010eb812014-10-25 18:06:49 -070057double drivetrain_translate(int32_t in) {
Austin Schuhdb516032014-12-28 00:12:38 -080058 return static_cast<double>(in) /
Daniel Pettiadf38432015-01-26 17:13:35 -080059 (256.0 /*cpr*/ * 4.0 /*4x*/) *
60 (20.0 / 50.0 /*output stage*/) *
Austin Schuhdb516032014-12-28 00:12:38 -080061 // * constants::GetValues().drivetrain_encoder_ratio
Daniel Pettiadf38432015-01-26 17:13:35 -080062 (4 /*wheel diameter*/ * 2.54 / 100.0 * M_PI);
63}
64
65double arm_translate(int32_t in) {
66 return static_cast<double>(in) /
67 (512.0 /*cpr*/ * 4.0 /*4x*/) *
68 (14.0 / 17.0 /*output sprockets*/) *
69 (18.0 / 48.0 /*encoder pulleys*/) *
70 (2 * M_PI /*radians*/);
71}
72
Brian Silverman8bca4a92015-02-05 15:19:06 -050073double arm_pot_translate(double voltage) {
74 return voltage /
Daniel Pettiadf38432015-01-26 17:13:35 -080075 (14.0 / 17.0 /*output sprockets*/) *
76 (5.0 /*volts*/ / 5.0 /*turns*/) *
77 (2 * M_PI /*radians*/);
78}
79
80double elevator_translate(int32_t in) {
81 return static_cast<double>(in) /
82 (512.0 /*cpr*/ * 4.0 /*4x*/) *
83 (14.0 / 84.0 /*output stage*/) *
84 (32 * 5 / 2.54 / 10 /*pulley circumference (in)*/);
85}
86
Brian Silverman8bca4a92015-02-05 15:19:06 -050087double elevator_pot_translate(double voltage) {
88 return voltage /
Daniel Pettiadf38432015-01-26 17:13:35 -080089 (32 * 5 / 2.54 / 10 /*pulley circumference (in)*/) *
90 (5.0 /*volts*/ / 5.0 /*turns*/);
91}
92
93double claw_translate(int32_t in) {
94 return static_cast<double>(in) /
95 (512.0 /*cpr*/ * 4.0 /*4x*/) *
96 (16.0 / 72.0 /*output sprockets*/) *
97 (2 * M_PI /*radians*/);
98}
99
Brian Silverman8bca4a92015-02-05 15:19:06 -0500100double claw_pot_translate(double voltage) {
101 return voltage /
Daniel Pettiadf38432015-01-26 17:13:35 -0800102 (16.0 / 72.0 /*output sprockets*/) *
103 (5.0 /*volts*/ / 5.0 /*turns*/) *
104 (2 * M_PI /*radians*/);
Austin Schuh010eb812014-10-25 18:06:49 -0700105}
106
Brian Silverman335c20e2015-01-26 21:47:58 -0500107static const double kMaximumEncoderPulsesPerSecond =
108 19500.0 /* free speed RPM */ * 12.0 / 56.0 /* belt reduction */ /
109 60.0 /* seconds / minute */ * 256.0 /* CPR */ *
110 4.0 /* index pulse = 1/4 cycle */;
111
Austin Schuh010eb812014-10-25 18:06:49 -0700112class SensorReader {
113 public:
Brian Silverman1f90d672015-01-26 20:20:45 -0500114 SensorReader() {
Brian Silverman335c20e2015-01-26 21:47:58 -0500115 // Set it to filter out anything shorter than 1/4 of the minimum pulse width
116 // we should ever see.
117 filter_.SetPeriodNanoSeconds(
118 static_cast<int>(1 / 4.0 / kMaximumEncoderPulsesPerSecond * 1e9 + 0.5));
119 }
120
121 void set_arm_left_encoder(::std::unique_ptr<Encoder> encoder) {
122 filter_.Add(encoder.get());
123 arm_left_encoder_.set_encoder(::std::move(encoder));
124 }
125
126 void set_arm_left_index(::std::unique_ptr<DigitalSource> index) {
127 filter_.Add(index.get());
128 arm_left_encoder_.set_index(::std::move(index));
129 }
130
131 void set_arm_left_potentiometer(
132 ::std::unique_ptr<AnalogInput> potentiometer) {
133 arm_left_encoder_.set_potentiometer(::std::move(potentiometer));
134 }
135
136 void set_arm_right_encoder(::std::unique_ptr<Encoder> encoder) {
137 filter_.Add(encoder.get());
138 arm_right_encoder_.set_encoder(::std::move(encoder));
139 }
140
141 void set_arm_right_index(::std::unique_ptr<DigitalSource> index) {
142 filter_.Add(index.get());
143 arm_right_encoder_.set_index(::std::move(index));
144 }
145
146 void set_arm_right_potentiometer(
147 ::std::unique_ptr<AnalogInput> potentiometer) {
148 arm_right_encoder_.set_potentiometer(::std::move(potentiometer));
149 }
150
151 void set_elevator_left_encoder(::std::unique_ptr<Encoder> encoder) {
152 filter_.Add(encoder.get());
153 elevator_left_encoder_.set_encoder(::std::move(encoder));
154 }
155
156 void set_elevator_left_index(::std::unique_ptr<DigitalSource> index) {
157 filter_.Add(index.get());
158 elevator_left_encoder_.set_index(::std::move(index));
159 }
160
161 void set_elevator_left_potentiometer(
162 ::std::unique_ptr<AnalogInput> potentiometer) {
163 elevator_left_encoder_.set_potentiometer(::std::move(potentiometer));
164 }
165
166 void set_elevator_right_encoder(::std::unique_ptr<Encoder> encoder) {
167 filter_.Add(encoder.get());
168 elevator_right_encoder_.set_encoder(::std::move(encoder));
169 }
170
171 void set_elevator_right_index(::std::unique_ptr<DigitalSource> index) {
172 filter_.Add(index.get());
173 elevator_right_encoder_.set_index(::std::move(index));
174 }
175
176 void set_elevator_right_potentiometer(
177 ::std::unique_ptr<AnalogInput> potentiometer) {
178 elevator_right_encoder_.set_potentiometer(::std::move(potentiometer));
179 }
180
181 void set_wrist_encoder(::std::unique_ptr<Encoder> encoder) {
182 filter_.Add(encoder.get());
183 wrist_encoder_.set_encoder(::std::move(encoder));
184 }
185
186 void set_wrist_index(::std::unique_ptr<DigitalSource> index) {
187 filter_.Add(index.get());
188 wrist_encoder_.set_index(::std::move(index));
189 }
190
191 void set_wrist_potentiometer(::std::unique_ptr<AnalogInput> potentiometer) {
192 wrist_encoder_.set_potentiometer(::std::move(potentiometer));
Austin Schuh010eb812014-10-25 18:06:49 -0700193 }
194
Brian Silverman1f90d672015-01-26 20:20:45 -0500195 void set_left_encoder(::std::unique_ptr<Encoder> left_encoder) {
196 left_encoder_ = ::std::move(left_encoder);
197 }
198
199 void set_right_encoder(::std::unique_ptr<Encoder> right_encoder) {
200 right_encoder_ = ::std::move(right_encoder);
201 }
202
Brian Silverman335c20e2015-01-26 21:47:58 -0500203 // All of the DMA-related set_* calls must be made before this, and it doesn't
204 // hurt to do all of them.
205 void set_dma(::std::unique_ptr<DMA> dma) {
206 dma_synchronizer_.reset(new DMASynchronizer(::std::move(dma)));
207 dma_synchronizer_->Add(&arm_left_encoder_);
208 dma_synchronizer_->Add(&arm_right_encoder_);
209 dma_synchronizer_->Add(&elevator_left_encoder_);
210 dma_synchronizer_->Add(&elevator_right_encoder_);
211 }
212
Austin Schuh010eb812014-10-25 18:06:49 -0700213 void operator()() {
Brian Silverman2fe007c2014-12-28 12:20:01 -0800214 ::aos::SetCurrentThreadName("SensorReader");
215
Brian Silverman335c20e2015-01-26 21:47:58 -0500216 wrist_encoder_.Start();
217 dma_synchronizer_->Start();
Austin Schuh010eb812014-10-25 18:06:49 -0700218
Brian Silverman2fe007c2014-12-28 12:20:01 -0800219 ::aos::SetCurrentThreadRealtimePriority(kPriority);
Austin Schuh010eb812014-10-25 18:06:49 -0700220 while (run_) {
Brian Silverman20141f92015-01-05 17:39:01 -0800221 ::aos::time::PhasedLoopXMS(5, 9000);
Austin Schuh010eb812014-10-25 18:06:49 -0700222 RunIteration();
Austin Schuh010eb812014-10-25 18:06:49 -0700223 }
Brian Silverman335c20e2015-01-26 21:47:58 -0500224
225 wrist_encoder_.Stop();
Austin Schuh010eb812014-10-25 18:06:49 -0700226 }
227
228 void RunIteration() {
Austin Schuh010eb812014-10-25 18:06:49 -0700229 DriverStation *ds = DriverStation::GetInstance();
230
Austin Schuhdb516032014-12-28 00:12:38 -0800231 if (ds->IsSysActive()) {
Austin Schuh010eb812014-10-25 18:06:49 -0700232 auto message = ::aos::controls::output_check_received.MakeMessage();
233 // TODO(brians): Actually read a pulse value from the roboRIO.
234 message->pwm_value = 0;
235 message->pulse_length = -1;
236 LOG_STRUCT(DEBUG, "received", *message);
237 message.Send();
238 }
239
Brian Silvermanada5f2c2015-02-01 02:41:14 -0500240 drivetrain_queue.position.MakeWithBuilder()
Austin Schuh010eb812014-10-25 18:06:49 -0700241 .right_encoder(drivetrain_translate(right_encoder_->GetRaw()))
242 .left_encoder(-drivetrain_translate(left_encoder_->GetRaw()))
Austin Schuh010eb812014-10-25 18:06:49 -0700243 .battery_voltage(ds->GetBatteryVoltage())
244 .Send();
245
Brian Silvermand8f403a2014-12-13 19:12:04 -0500246 // Signal that we are alive.
Austin Schuh010eb812014-10-25 18:06:49 -0700247 ::aos::controls::sensor_generation.MakeWithBuilder()
248 .reader_pid(getpid())
249 .cape_resets(0)
250 .Send();
Brian Silverman335c20e2015-01-26 21:47:58 -0500251
252 dma_synchronizer_->RunIteration();
253
254 {
255 auto fridge_message = fridge_queue.position.MakeMessage();
256 CopyPotAndIndexPosition(arm_left_encoder_, &fridge_message->arm.left,
257 arm_translate, arm_pot_translate, false);
258 CopyPotAndIndexPosition(arm_right_encoder_, &fridge_message->arm.right,
259 arm_translate, arm_pot_translate, true);
260 CopyPotAndIndexPosition(
261 elevator_left_encoder_, &fridge_message->elevator.left,
262 elevator_translate, elevator_pot_translate, false);
263 CopyPotAndIndexPosition(elevator_right_encoder_,
264 &fridge_message->elevator.right,
265 elevator_translate, elevator_pot_translate, true);
266 fridge_message.Send();
267 }
268
269 {
270 auto claw_message = claw_queue.position.MakeMessage();
271 CopyPotAndIndexPosition(wrist_encoder_, &claw_message->joint,
272 claw_translate, claw_pot_translate, false);
273 claw_message.Send();
274 }
Austin Schuh010eb812014-10-25 18:06:49 -0700275 }
276
277 void Quit() { run_ = false; }
278
279 private:
Brian Silverman335c20e2015-01-26 21:47:58 -0500280 static const int kPriority = 30;
281 static const int kInterruptPriority = 55;
282
283 void CopyPotAndIndexPosition(
284 const DMAEncoderAndPotentiometer &encoder, PotAndIndexPosition *position,
285 ::std::function<double(int32_t)> encoder_translate,
286 ::std::function<double(double)> pot_translate, bool reverse) {
287 const double multiplier = reverse ? -1.0 : 1.0;
288 position->encoder =
289 multiplier * encoder_translate(encoder.polled_encoder_value());
290 position->pot =
291 multiplier * pot_translate(encoder.polled_potentiometer_voltage());
292 position->latched_encoder =
293 multiplier * encoder_translate(encoder.last_encoder_value());
294 position->latched_pot =
295 multiplier * pot_translate(encoder.last_potentiometer_voltage());
296 position->index_pulses = encoder.index_posedge_count();
297 }
298
299 void CopyPotAndIndexPosition(
300 const InterruptEncoderAndPotentiometer &encoder,
301 PotAndIndexPosition *position,
302 ::std::function<double(int32_t)> encoder_translate,
303 ::std::function<double(double)> pot_translate, bool reverse) {
304 const double multiplier = reverse ? -1.0 : 1.0;
305 position->encoder =
306 multiplier * encoder_translate(encoder.encoder()->GetRaw());
307 position->pot =
308 multiplier * pot_translate(encoder.potentiometer()->GetVoltage());
309 position->latched_encoder =
310 multiplier * encoder_translate(encoder.last_encoder_value());
311 position->latched_pot =
312 multiplier * pot_translate(encoder.last_potentiometer_voltage());
313 position->index_pulses = encoder.index_posedge_count();
314 }
315
316
317 ::std::unique_ptr<DMASynchronizer> dma_synchronizer_;
318
319 DMAEncoderAndPotentiometer arm_left_encoder_, arm_right_encoder_,
320 elevator_left_encoder_, elevator_right_encoder_;
321
322 InterruptEncoderAndPotentiometer wrist_encoder_{kInterruptPriority};
323
Austin Schuh010eb812014-10-25 18:06:49 -0700324 ::std::unique_ptr<Encoder> left_encoder_;
325 ::std::unique_ptr<Encoder> right_encoder_;
Austin Schuh010eb812014-10-25 18:06:49 -0700326
Brian Silverman1f90d672015-01-26 20:20:45 -0500327 ::std::atomic<bool> run_{true};
Austin Schuh010eb812014-10-25 18:06:49 -0700328 DigitalGlitchFilter filter_;
329};
330
Brian Silvermand8f403a2014-12-13 19:12:04 -0500331class SolenoidWriter {
Austin Schuh010eb812014-10-25 18:06:49 -0700332 public:
Brian Silvermand8f403a2014-12-13 19:12:04 -0500333 SolenoidWriter(const ::std::unique_ptr<BufferedPcm> &pcm)
Daniel Pettiadf38432015-01-26 17:13:35 -0800334 : pcm_(pcm),
335 fridge_(".frc971.control_loops.fridge.output"),
336 claw_(".frc971.control_loops.claw.output") {}
Brian Silvermand8f403a2014-12-13 19:12:04 -0500337
Daniel Pettiadf38432015-01-26 17:13:35 -0800338 void set_fridge_grabbers_top_front(::std::unique_ptr<BufferedSolenoid> s) {
339 fridge_grabbers_top_front_ = ::std::move(s);
Austin Schuh010eb812014-10-25 18:06:49 -0700340 }
341
Daniel Pettiadf38432015-01-26 17:13:35 -0800342 void set_fridge_grabbers_top_back(::std::unique_ptr<BufferedSolenoid> s) {
343 fridge_grabbers_top_back_ = ::std::move(s);
344 }
345
346 void set_fridge_grabbers_bottom_front(
347 ::std::unique_ptr<BufferedSolenoid> s) {
348 fridge_grabbers_bottom_front_ = ::std::move(s);
349 }
350
351 void set_fridge_grabbers_bottom_back(
352 ::std::unique_ptr<BufferedSolenoid> s) {
353 fridge_grabbers_bottom_back_ = ::std::move(s);
354 }
355
356 void set_claw_pinchers(::std::unique_ptr<BufferedSolenoid> s) {
357 claw_pinchers_ = ::std::move(s);
Brian Silvermand8f403a2014-12-13 19:12:04 -0500358 }
Austin Schuh010eb812014-10-25 18:06:49 -0700359
Brian Silvermand8f403a2014-12-13 19:12:04 -0500360 void operator()() {
361 ::aos::SetCurrentThreadName("Solenoids");
362 ::aos::SetCurrentThreadRealtimePriority(30);
363
364 while (run_) {
365 ::aos::time::PhasedLoopXMS(20, 1000);
366
367 {
Daniel Pettiadf38432015-01-26 17:13:35 -0800368 fridge_.FetchLatest();
369 if (fridge_.get()) {
370 LOG_STRUCT(DEBUG, "solenoids", *fridge_);
371 fridge_grabbers_top_front_->Set(fridge_->grabbers.top_front);
372 fridge_grabbers_top_back_->Set(fridge_->grabbers.top_back);
373 fridge_grabbers_bottom_front_->Set(fridge_->grabbers.bottom_front);
374 fridge_grabbers_bottom_back_->Set(fridge_->grabbers.bottom_back);
375 }
376 }
377
378 {
379 claw_.FetchLatest();
380 if (claw_.get()) {
381 LOG_STRUCT(DEBUG, "solenoids", *claw_);
382 claw_pinchers_->Set(claw_->rollers_closed);
Brian Silvermand8f403a2014-12-13 19:12:04 -0500383 }
384 }
385
Brian Silvermand8f403a2014-12-13 19:12:04 -0500386 pcm_->Flush();
Austin Schuh010eb812014-10-25 18:06:49 -0700387 }
388 }
389
Brian Silvermand8f403a2014-12-13 19:12:04 -0500390 void Quit() { run_ = false; }
Austin Schuh010eb812014-10-25 18:06:49 -0700391
Brian Silvermand8f403a2014-12-13 19:12:04 -0500392 private:
393 const ::std::unique_ptr<BufferedPcm> &pcm_;
Daniel Pettiadf38432015-01-26 17:13:35 -0800394 ::std::unique_ptr<BufferedSolenoid> fridge_grabbers_top_front_;
395 ::std::unique_ptr<BufferedSolenoid> fridge_grabbers_top_back_;
396 ::std::unique_ptr<BufferedSolenoid> fridge_grabbers_bottom_front_;
397 ::std::unique_ptr<BufferedSolenoid> fridge_grabbers_bottom_back_;
398 ::std::unique_ptr<BufferedSolenoid> claw_pinchers_;
Austin Schuh010eb812014-10-25 18:06:49 -0700399
Daniel Pettiadf38432015-01-26 17:13:35 -0800400 ::aos::Queue<::frc971::control_loops::FridgeQueue::Output> fridge_;
401 ::aos::Queue<::frc971::control_loops::ClawQueue::Output> claw_;
Austin Schuh010eb812014-10-25 18:06:49 -0700402
Brian Silvermand8f403a2014-12-13 19:12:04 -0500403 ::std::atomic<bool> run_{true};
404};
405
406class DrivetrainWriter : public LoopOutputHandler {
407 public:
408 void set_left_drivetrain_talon(::std::unique_ptr<Talon> t) {
409 left_drivetrain_talon_ = ::std::move(t);
Austin Schuh010eb812014-10-25 18:06:49 -0700410 }
411
Brian Silvermand8f403a2014-12-13 19:12:04 -0500412 void set_right_drivetrain_talon(::std::unique_ptr<Talon> t) {
413 right_drivetrain_talon_ = ::std::move(t);
414 }
Austin Schuh010eb812014-10-25 18:06:49 -0700415
Brian Silvermand8f403a2014-12-13 19:12:04 -0500416 private:
417 virtual void Read() override {
Brian Silvermanada5f2c2015-02-01 02:41:14 -0500418 ::frc971::control_loops::drivetrain_queue.output.FetchAnother();
Brian Silvermand8f403a2014-12-13 19:12:04 -0500419 }
420
421 virtual void Write() override {
Brian Silvermanada5f2c2015-02-01 02:41:14 -0500422 auto &queue = ::frc971::control_loops::drivetrain_queue.output;
Brian Silvermand8f403a2014-12-13 19:12:04 -0500423 LOG_STRUCT(DEBUG, "will output", *queue);
424 left_drivetrain_talon_->Set(-queue->left_voltage / 12.0);
425 right_drivetrain_talon_->Set(queue->right_voltage / 12.0);
426 }
427
428 virtual void Stop() override {
429 LOG(WARNING, "drivetrain output too old\n");
430 left_drivetrain_talon_->Disable();
431 right_drivetrain_talon_->Disable();
432 }
433
Austin Schuh010eb812014-10-25 18:06:49 -0700434 ::std::unique_ptr<Talon> left_drivetrain_talon_;
Brian Silvermand8f403a2014-12-13 19:12:04 -0500435 ::std::unique_ptr<Talon> right_drivetrain_talon_;
436};
437
Daniel Pettiadf38432015-01-26 17:13:35 -0800438class FridgeWriter : public LoopOutputHandler {
439 public:
440 void set_left_arm_talon(::std::unique_ptr<Talon> t) {
441 left_arm_talon_ = ::std::move(t);
442 }
443
444 void set_right_arm_talon(::std::unique_ptr<Talon> t) {
445 right_arm_talon_ = ::std::move(t);
446 }
447
448 void set_left_elevator_talon(::std::unique_ptr<Talon> t) {
449 left_elevator_talon_ = ::std::move(t);
450 }
451
452 void set_right_elevator_talon(::std::unique_ptr<Talon> t) {
453 right_elevator_talon_ = ::std::move(t);
454 }
455
456 private:
457 virtual void Read() override {
458 ::frc971::control_loops::fridge_queue.output.FetchAnother();
459 }
460
461 virtual void Write() override {
462 auto &queue = ::frc971::control_loops::fridge_queue.output;
463 LOG_STRUCT(DEBUG, "will output", *queue);
464 left_arm_talon_->Set(-queue->left_arm / 12.0);
465 right_arm_talon_->Set(queue->right_arm / 12.0);
466 left_elevator_talon_->Set(-queue->left_elevator / 12.0);
467 right_elevator_talon_->Set(queue->right_elevator / 12.0);
468 }
469
470 virtual void Stop() override {
471 LOG(WARNING, "Fridge output too old.\n");
472 left_arm_talon_->Disable();
473 right_arm_talon_->Disable();
474 left_elevator_talon_->Disable();
475 right_elevator_talon_->Disable();
476 }
477
478 ::std::unique_ptr<Talon> left_arm_talon_;
479 ::std::unique_ptr<Talon> right_arm_talon_;
480 ::std::unique_ptr<Talon> left_elevator_talon_;
481 ::std::unique_ptr<Talon> right_elevator_talon_;
482};
483
484class ClawWriter : public LoopOutputHandler {
485 public:
486 void set_intake_talon(::std::unique_ptr<Talon> t) {
487 intake_talon_ = ::std::move(t);
488 }
489
490 void set_wrist_talon(::std::unique_ptr<Talon> t) {
491 wrist_talon_ = ::std::move(t);
492 }
493
494 private:
495 virtual void Read() override {
496 ::frc971::control_loops::claw_queue.output.FetchAnother();
497 }
498
499 virtual void Write() override {
500 auto &queue = ::frc971::control_loops::claw_queue.output;
501 LOG_STRUCT(DEBUG, "will output", *queue);
502 intake_talon_->Set(queue->intake_voltage / 12.0);
503 wrist_talon_->Set(queue->voltage / 12.0);
504 }
505
506 virtual void Stop() override {
507 LOG(WARNING, "Claw output too old.\n");
508 intake_talon_->Disable();
509 wrist_talon_->Disable();
510 }
511
512 ::std::unique_ptr<Talon> intake_talon_;
513 ::std::unique_ptr<Talon> wrist_talon_;
514};
515
Brian Silverman1f90d672015-01-26 20:20:45 -0500516// TODO(brian): Replace this with ::std::make_unique once all our toolchains
517// have support.
518template <class T, class... U>
519std::unique_ptr<T> make_unique(U &&... u) {
520 return std::unique_ptr<T>(new T(std::forward<U>(u)...));
521}
522
Austin Schuh010eb812014-10-25 18:06:49 -0700523class WPILibRobot : public RobotBase {
524 public:
525 virtual void StartCompetition() {
Brian Silvermand8f403a2014-12-13 19:12:04 -0500526 ::aos::InitNRT();
Brian Silverman2fe007c2014-12-28 12:20:01 -0800527 ::aos::SetCurrentThreadName("StartCompetition");
Brian Silvermand8f403a2014-12-13 19:12:04 -0500528
Brian Silverman98f6ee22015-01-26 17:50:12 -0500529 JoystickSender joystick_sender;
Austin Schuh010eb812014-10-25 18:06:49 -0700530 ::std::thread joystick_thread(::std::ref(joystick_sender));
Brian Silvermand8f403a2014-12-13 19:12:04 -0500531 ::std::unique_ptr<Compressor> compressor(new Compressor());
532 compressor->SetClosedLoopControl(true);
533
Brian Silverman98f6ee22015-01-26 17:50:12 -0500534 SensorReader reader;
Brian Silverman1f90d672015-01-26 20:20:45 -0500535 // TODO(sensors): Replace all the 99s with real port numbers.
Brian Silverman335c20e2015-01-26 21:47:58 -0500536 reader.set_arm_left_encoder(
537 make_unique<Encoder>(99, 99, false, Encoder::k4X));
538 reader.set_arm_left_index(make_unique<DigitalInput>(99));
539 reader.set_arm_left_potentiometer(make_unique<AnalogInput>(99));
540 reader.set_arm_right_encoder(
541 make_unique<Encoder>(99, 99, false, Encoder::k4X));
542 reader.set_arm_right_index(make_unique<DigitalInput>(99));
543 reader.set_arm_right_potentiometer(make_unique<AnalogInput>(99));
544 reader.set_elevator_left_encoder(
545 make_unique<Encoder>(99, 99, false, Encoder::k4X));
546 reader.set_elevator_left_index(make_unique<DigitalInput>(99));
547 reader.set_elevator_left_potentiometer(make_unique<AnalogInput>(99));
548 reader.set_elevator_right_encoder(
549 make_unique<Encoder>(99, 99, false, Encoder::k4X));
550 reader.set_elevator_right_index(make_unique<DigitalInput>(99));
551 reader.set_elevator_right_potentiometer(make_unique<AnalogInput>(99));
552 reader.set_wrist_encoder(make_unique<Encoder>(99, 99, false, Encoder::k4X));
553 reader.set_wrist_index(make_unique<DigitalInput>(99));
554 reader.set_wrist_potentiometer(make_unique<AnalogInput>(99));
Brian Silverman1f90d672015-01-26 20:20:45 -0500555 reader.set_left_encoder(make_unique<Encoder>(99, 99, false, Encoder::k4X));
556 reader.set_right_encoder(make_unique<Encoder>(99, 99, false, Encoder::k4X));
Brian Silverman335c20e2015-01-26 21:47:58 -0500557 reader.set_dma(make_unique<DMA>());
Brian Silverman98f6ee22015-01-26 17:50:12 -0500558 ::std::thread reader_thread(::std::ref(reader));
559 GyroSender gyro_sender;
560 ::std::thread gyro_thread(::std::ref(gyro_sender));
561
562 DrivetrainWriter drivetrain_writer;
Brian Silvermand8f403a2014-12-13 19:12:04 -0500563 drivetrain_writer.set_left_drivetrain_talon(
564 ::std::unique_ptr<Talon>(new Talon(5)));
565 drivetrain_writer.set_right_drivetrain_talon(
566 ::std::unique_ptr<Talon>(new Talon(2)));
567 ::std::thread drivetrain_writer_thread(::std::ref(drivetrain_writer));
568
Daniel Pettiadf38432015-01-26 17:13:35 -0800569 // TODO(sensors): Get real PWM output and relay numbers for the fridge and
570 // claw.
571 FridgeWriter fridge_writer;
572 fridge_writer.set_left_arm_talon(
573 ::std::unique_ptr<Talon>(new Talon(99)));
574 fridge_writer.set_right_arm_talon(
575 ::std::unique_ptr<Talon>(new Talon(99)));
576 fridge_writer.set_left_elevator_talon(
577 ::std::unique_ptr<Talon>(new Talon(99)));
578 fridge_writer.set_right_elevator_talon(
579 ::std::unique_ptr<Talon>(new Talon(99)));
580 ::std::thread fridge_writer_thread(::std::ref(fridge_writer));
581
582 ClawWriter claw_writer;
583 claw_writer.set_intake_talon(
584 ::std::unique_ptr<Talon>(new Talon(99)));
585 claw_writer.set_wrist_talon(
586 ::std::unique_ptr<Talon>(new Talon(99)));
587 ::std::thread claw_writer_thread(::std::ref(claw_writer));
588
589 ::std::unique_ptr<::frc971::wpilib::BufferedPcm> pcm(
590 new ::frc971::wpilib::BufferedPcm());
Brian Silverman98f6ee22015-01-26 17:50:12 -0500591 SolenoidWriter solenoid_writer(pcm);
Daniel Pettiadf38432015-01-26 17:13:35 -0800592 solenoid_writer.set_fridge_grabbers_top_front(pcm->MakeSolenoid(99));
593 solenoid_writer.set_fridge_grabbers_top_back(pcm->MakeSolenoid(99));
594 solenoid_writer.set_fridge_grabbers_bottom_front(pcm->MakeSolenoid(99));
595 solenoid_writer.set_fridge_grabbers_bottom_back(pcm->MakeSolenoid(99));
596 solenoid_writer.set_claw_pinchers(pcm->MakeSolenoid(99));
Brian Silvermand8f403a2014-12-13 19:12:04 -0500597 ::std::thread solenoid_thread(::std::ref(solenoid_writer));
598
599 // Wait forever. Not much else to do...
600 PCHECK(select(0, nullptr, nullptr, nullptr, nullptr));
601
Austin Schuh010eb812014-10-25 18:06:49 -0700602 LOG(ERROR, "Exiting WPILibRobot\n");
Brian Silverman07ec88e2014-12-28 00:13:08 -0800603
Austin Schuh010eb812014-10-25 18:06:49 -0700604 joystick_sender.Quit();
605 joystick_thread.join();
Brian Silvermand8f403a2014-12-13 19:12:04 -0500606 reader.Quit();
607 reader_thread.join();
Brian Silverman07ec88e2014-12-28 00:13:08 -0800608 gyro_sender.Quit();
609 gyro_thread.join();
Brian Silvermand8f403a2014-12-13 19:12:04 -0500610
611 drivetrain_writer.Quit();
612 drivetrain_writer_thread.join();
Brian Silvermand8f403a2014-12-13 19:12:04 -0500613 solenoid_writer.Quit();
614 solenoid_thread.join();
615
Austin Schuh010eb812014-10-25 18:06:49 -0700616 ::aos::Cleanup();
617 }
618};
619
Brian Silverman98f6ee22015-01-26 17:50:12 -0500620} // namespace wpilib
621} // namespace frc971
Austin Schuhdb516032014-12-28 00:12:38 -0800622
Brian Silverman98f6ee22015-01-26 17:50:12 -0500623
624START_ROBOT_CLASS(::frc971::wpilib::WPILibRobot);