blob: 52a6989c7601e60b5f81b9868dfdbf9840ccb385 [file] [log] [blame]
Austin Schuh8347cb62017-04-08 14:37:34 -07001#include <inttypes.h>
Campbell Crowleyae6e8422017-02-05 12:38:50 -08002#include <stdio.h>
3#include <string.h>
4#include <unistd.h>
Campbell Crowleyae6e8422017-02-05 12:38:50 -08005
Campbell Crowleyae6e8422017-02-05 12:38:50 -08006#include <array>
Austin Schuh8347cb62017-04-08 14:37:34 -07007#include <chrono>
Brian Silverman50826c02017-02-18 14:40:25 -08008#include <cmath>
Austin Schuh8347cb62017-04-08 14:37:34 -07009#include <functional>
10#include <mutex>
11#include <thread>
Campbell Crowleyae6e8422017-02-05 12:38:50 -080012
Campbell Crowleyae6e8422017-02-05 12:38:50 -080013#include "AnalogInput.h"
14#include "Compressor.h"
Austin Schuh8347cb62017-04-08 14:37:34 -070015#include "Counter.h"
Campbell Crowleyae6e8422017-02-05 12:38:50 -080016#include "DigitalGlitchFilter.h"
Austin Schuh8347cb62017-04-08 14:37:34 -070017#include "DriverStation.h"
18#include "Encoder.h"
19#include "Relay.h"
20#include "Servo.h"
21#include "VictorSP.h"
Campbell Crowleyae6e8422017-02-05 12:38:50 -080022#undef ERROR
23
John Park33858a32018-09-28 23:05:48 -070024#include "aos/commonmath.h"
25#include "aos/logging/logging.h"
26#include "aos/logging/queue_logging.h"
27#include "aos/robot_state/robot_state.q.h"
28#include "aos/stl_mutex/stl_mutex.h"
29#include "aos/time/time.h"
30#include "aos/util/compiler_memory_barrier.h"
31#include "aos/util/log_interval.h"
32#include "aos/util/phased_loop.h"
33#include "aos/util/wrapping_counter.h"
Campbell Crowleyae6e8422017-02-05 12:38:50 -080034#include "aos/linux_code/init.h"
Campbell Crowleyae6e8422017-02-05 12:38:50 -080035
Philipp Schrader996a2a22017-02-22 05:02:48 +000036#include "frc971/autonomous/auto.q.h"
Campbell Crowleyae6e8422017-02-05 12:38:50 -080037#include "frc971/control_loops/control_loops.q.h"
38#include "frc971/control_loops/drivetrain/drivetrain.q.h"
Austin Schuh8347cb62017-04-08 14:37:34 -070039#include "frc971/wpilib/ADIS16448.h"
40#include "frc971/wpilib/buffered_pcm.h"
41#include "frc971/wpilib/buffered_solenoid.h"
42#include "frc971/wpilib/dma.h"
43#include "frc971/wpilib/dma_edge_counting.h"
44#include "frc971/wpilib/encoder_and_potentiometer.h"
45#include "frc971/wpilib/interrupt_edge_counting.h"
46#include "frc971/wpilib/joystick_sender.h"
47#include "frc971/wpilib/logging.q.h"
48#include "frc971/wpilib/loop_output_handler.h"
49#include "frc971/wpilib/pdp_fetcher.h"
50#include "frc971/wpilib/wpilib_interface.h"
51#include "frc971/wpilib/wpilib_robot_base.h"
Campbell Crowleyae6e8422017-02-05 12:38:50 -080052#include "y2017/constants.h"
Campbell Crowleyae6e8422017-02-05 12:38:50 -080053#include "y2017/control_loops/superstructure/superstructure.q.h"
Campbell Crowleyae6e8422017-02-05 12:38:50 -080054
Campbell Crowleyae6e8422017-02-05 12:38:50 -080055#ifndef M_PI
56#define M_PI 3.14159265358979323846
57#endif
58
59using ::frc971::control_loops::drivetrain_queue;
60using ::y2017::control_loops::superstructure_queue;
Brian Silverman052e69d2017-02-12 16:19:55 -080061using ::y2017::constants::Values;
Austin Schuh8347cb62017-04-08 14:37:34 -070062using ::aos::monotonic_clock;
63namespace chrono = ::std::chrono;
Campbell Crowleyae6e8422017-02-05 12:38:50 -080064
65namespace y2017 {
66namespace wpilib {
67namespace {
Brian Silverman052e69d2017-02-12 16:19:55 -080068
Campbell Crowleyae6e8422017-02-05 12:38:50 -080069constexpr double kMaxBringupPower = 12.0;
Campbell Crowleyae6e8422017-02-05 12:38:50 -080070
71// TODO(Brian): Fix the interpretation of the result of GetRaw here and in the
72// DMA stuff and then removing the * 2.0 in *_translate.
73// The low bit is direction.
74
75// TODO(brian): Replace this with ::std::make_unique once all our toolchains
76// have support.
77template <class T, class... U>
78std::unique_ptr<T> make_unique(U &&... u) {
79 return std::unique_ptr<T>(new T(std::forward<U>(u)...));
80}
81
Brian Silverman052e69d2017-02-12 16:19:55 -080082// TODO(brian): Use ::std::max instead once we have C++14 so that can be
83// constexpr.
84template <typename T>
85constexpr T max(T a, T b) {
86 return (a > b) ? a : b;
87}
88template <typename T, typename... Rest>
89constexpr T max(T a, T b, T c, Rest... rest) {
90 return max(max(a, b), c, rest...);
91}
Campbell Crowleyae6e8422017-02-05 12:38:50 -080092
Campbell Crowleyae6e8422017-02-05 12:38:50 -080093double drivetrain_translate(int32_t in) {
Brian Silverman052e69d2017-02-12 16:19:55 -080094 return static_cast<double>(in) /
95 Values::kDrivetrainEncoderCountsPerRevolution *
96 Values::kDrivetrainEncoderRatio * 2.0 * M_PI;
Campbell Crowleyae6e8422017-02-05 12:38:50 -080097}
98
99double drivetrain_velocity_translate(double in) {
Brian Silverman052e69d2017-02-12 16:19:55 -0800100 return (1.0 / in) / Values::kDrivetrainCyclesPerRevolution *
101 Values::kDrivetrainEncoderRatio * 2.0 * M_PI;
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800102}
103
Brian Silverman50826c02017-02-18 14:40:25 -0800104// TODO(Travis): Make sure the number of turns is right.
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800105double intake_pot_translate(double voltage) {
Brian Silverman50826c02017-02-18 14:40:25 -0800106 return voltage * Values::kIntakePotRatio * (3.0 /*turns*/ / 5.0 /*volts*/) *
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800107 (2 * M_PI /*radians*/);
108}
109
Brian Silverman052e69d2017-02-12 16:19:55 -0800110constexpr double kMaxFastEncoderPulsesPerSecond =
111 max(Values::kMaxDrivetrainEncoderPulsesPerSecond,
112 Values::kMaxShooterEncoderPulsesPerSecond);
113static_assert(kMaxFastEncoderPulsesPerSecond <= 1300000,
114 "fast encoders are too fast");
115constexpr double kMaxMediumEncoderPulsesPerSecond =
116 max(Values::kMaxIntakeEncoderPulsesPerSecond,
117 Values::kMaxTurretEncoderPulsesPerSecond,
118 Values::kMaxIndexerEncoderPulsesPerSecond);
119static_assert(kMaxMediumEncoderPulsesPerSecond <= 400000,
120 "medium encoders are too fast");
121constexpr double kMaxSlowEncoderPulsesPerSecond =
122 Values::kMaxHoodEncoderPulsesPerSecond;
123static_assert(kMaxSlowEncoderPulsesPerSecond <= 100000,
124 "slow encoders are too fast");
Brianef030df2017-03-05 15:06:04 -0800125static_assert(kMaxSlowEncoderPulsesPerSecond < kMaxMediumEncoderPulsesPerSecond,
126 "slow encoders are faster than medium?");
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800127
128// Class to send position messages with sensor readings to our loops.
129class SensorReader {
130 public:
131 SensorReader() {
Brian Silverman052e69d2017-02-12 16:19:55 -0800132 // Set to filter out anything shorter than 1/4 of the minimum pulse width
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800133 // we should ever see.
Brian Silverman052e69d2017-02-12 16:19:55 -0800134 fast_encoder_filter_.SetPeriodNanoSeconds(
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800135 static_cast<int>(1 / 4.0 /* built-in tolerance */ /
Brian Silverman052e69d2017-02-12 16:19:55 -0800136 kMaxFastEncoderPulsesPerSecond * 1e9 +
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800137 0.5));
Brian Silverman052e69d2017-02-12 16:19:55 -0800138 medium_encoder_filter_.SetPeriodNanoSeconds(
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800139 static_cast<int>(1 / 4.0 /* built-in tolerance */ /
Brian Silverman052e69d2017-02-12 16:19:55 -0800140 kMaxMediumEncoderPulsesPerSecond * 1e9 +
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800141 0.5));
Brianef030df2017-03-05 15:06:04 -0800142 hall_filter_.SetPeriodNanoSeconds(100000);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800143 }
144
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800145 void set_drivetrain_left_encoder(::std::unique_ptr<Encoder> encoder) {
Brian Silverman052e69d2017-02-12 16:19:55 -0800146 fast_encoder_filter_.Add(encoder.get());
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800147 drivetrain_left_encoder_ = ::std::move(encoder);
148 }
149
150 void set_drivetrain_right_encoder(::std::unique_ptr<Encoder> encoder) {
Brian Silverman052e69d2017-02-12 16:19:55 -0800151 fast_encoder_filter_.Add(encoder.get());
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800152 drivetrain_right_encoder_ = ::std::move(encoder);
153 }
154
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800155 void set_shooter_encoder(::std::unique_ptr<Encoder> encoder) {
Brian Silverman052e69d2017-02-12 16:19:55 -0800156 fast_encoder_filter_.Add(encoder.get());
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800157 shooter_encoder_ = ::std::move(encoder);
158 }
159
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800160 void set_intake_encoder(::std::unique_ptr<Encoder> encoder) {
Brian Silverman052e69d2017-02-12 16:19:55 -0800161 medium_encoder_filter_.Add(encoder.get());
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800162 intake_encoder_.set_encoder(::std::move(encoder));
163 }
164
165 void set_intake_potentiometer(::std::unique_ptr<AnalogInput> potentiometer) {
166 intake_encoder_.set_potentiometer(::std::move(potentiometer));
167 }
168
Brian Silverman50826c02017-02-18 14:40:25 -0800169 void set_intake_absolute(::std::unique_ptr<DigitalInput> input) {
170 intake_encoder_.set_absolute_pwm(::std::move(input));
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800171 }
172
Brian Silverman052e69d2017-02-12 16:19:55 -0800173 void set_indexer_encoder(::std::unique_ptr<Encoder> encoder) {
174 medium_encoder_filter_.Add(encoder.get());
Brianef030df2017-03-05 15:06:04 -0800175 indexer_counter_.set_encoder(encoder.get());
Brian Silverman052e69d2017-02-12 16:19:55 -0800176 indexer_encoder_ = ::std::move(encoder);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800177 }
178
Brianef030df2017-03-05 15:06:04 -0800179 void set_indexer_hall(::std::unique_ptr<DigitalInput> input) {
180 hall_filter_.Add(input.get());
181 indexer_counter_.set_input(input.get());
182 indexer_hall_ = ::std::move(input);
183 }
184
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800185 void set_turret_encoder(::std::unique_ptr<Encoder> encoder) {
Brian Silverman052e69d2017-02-12 16:19:55 -0800186 medium_encoder_filter_.Add(encoder.get());
Brianef030df2017-03-05 15:06:04 -0800187 turret_counter_.set_encoder(encoder.get());
188 turret_encoder_ = ::std::move(encoder);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800189 }
190
Brianef030df2017-03-05 15:06:04 -0800191 void set_turret_hall(::std::unique_ptr<DigitalInput> input) {
192 hall_filter_.Add(input.get());
193 turret_counter_.set_input(input.get());
194 turret_hall_ = ::std::move(input);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800195 }
196
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800197 void set_hood_encoder(::std::unique_ptr<Encoder> encoder) {
Brianef030df2017-03-05 15:06:04 -0800198 medium_encoder_filter_.Add(encoder.get());
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800199 hood_encoder_.set_encoder(::std::move(encoder));
200 }
201
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800202 void set_hood_index(::std::unique_ptr<DigitalInput> index) {
Brianef030df2017-03-05 15:06:04 -0800203 medium_encoder_filter_.Add(index.get());
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800204 hood_encoder_.set_index(::std::move(index));
205 }
206
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800207 void set_autonomous_mode(int i, ::std::unique_ptr<DigitalInput> sensor) {
208 autonomous_modes_.at(i) = ::std::move(sensor);
209 }
210
Austin Schuh8347cb62017-04-08 14:37:34 -0700211 void set_pwm_trigger(::std::unique_ptr<DigitalInput> pwm_trigger) {
212 medium_encoder_filter_.Add(pwm_trigger.get());
213 pwm_trigger_ = ::std::move(pwm_trigger);
214 }
215
216 // All of the DMA-related set_* calls must be made before this, and it
217 // doesn't
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800218 // hurt to do all of them.
219 void set_dma(::std::unique_ptr<DMA> dma) {
220 dma_synchronizer_.reset(
221 new ::frc971::wpilib::DMASynchronizer(::std::move(dma)));
Brianef030df2017-03-05 15:06:04 -0800222 dma_synchronizer_->Add(&indexer_counter_);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800223 dma_synchronizer_->Add(&hood_encoder_);
Brianef030df2017-03-05 15:06:04 -0800224 dma_synchronizer_->Add(&turret_counter_);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800225 }
226
Austin Schuh8347cb62017-04-08 14:37:34 -0700227 void RunPWMDetecter() {
228 ::aos::SetCurrentThreadRealtimePriority(41);
229
230 pwm_trigger_->RequestInterrupts();
231 // Rising edge only.
232 pwm_trigger_->SetUpSourceEdge(true, false);
233
234 monotonic_clock::time_point last_posedge_monotonic =
235 monotonic_clock::min_time;
236
237 while (run_) {
238 auto ret = pwm_trigger_->WaitForInterrupt(1.0, true);
239 if (ret == InterruptableSensorBase::WaitResult::kRisingEdge) {
240 // Grab all the clocks.
241 const double pwm_fpga_time = pwm_trigger_->ReadRisingTimestamp();
242
243 aos_compiler_memory_barrier();
244 const double fpga_time_before = GetFPGATime() * 1e-6;
245 aos_compiler_memory_barrier();
246 const monotonic_clock::time_point monotonic_now =
247 monotonic_clock::now();
248 aos_compiler_memory_barrier();
249 const double fpga_time_after = GetFPGATime() * 1e-6;
250 aos_compiler_memory_barrier();
251
252 const double fpga_offset =
253 (fpga_time_after + fpga_time_before) / 2.0 - pwm_fpga_time;
254
255 // Compute when the edge was.
256 const monotonic_clock::time_point monotonic_edge =
257 monotonic_now - chrono::duration_cast<chrono::nanoseconds>(
258 chrono::duration<double>(fpga_offset));
259
260 LOG(INFO, "Got PWM pulse %f spread, %f offset, %lld trigger\n",
261 fpga_time_after - fpga_time_before, fpga_offset,
262 monotonic_edge.time_since_epoch().count());
263
264 // Compute bounds on the timestep and sampling times.
265 const double fpga_sample_length = fpga_time_after - fpga_time_before;
266 const chrono::nanoseconds elapsed_time =
267 monotonic_edge - last_posedge_monotonic;
268
269 last_posedge_monotonic = monotonic_edge;
270
271 // Verify that the values are sane.
272 if (fpga_sample_length > 2e-5 || fpga_sample_length < 0) {
273 continue;
274 }
275 if (fpga_offset < 0 || fpga_offset > 0.00015) {
276 continue;
277 }
278 if (elapsed_time >
279 chrono::microseconds(5050) + chrono::microseconds(4) ||
280 elapsed_time <
281 chrono::microseconds(5050) - chrono::microseconds(4)) {
282 continue;
283 }
284 // Good edge!
285 {
286 ::std::unique_lock<::aos::stl_mutex> locker(tick_time_mutex_);
287 last_tick_time_monotonic_timepoint_ = last_posedge_monotonic;
288 last_period_ = elapsed_time;
289 }
290 } else {
291 LOG(INFO, "PWM triggered %d\n", ret);
292 }
293 }
294 pwm_trigger_->CancelInterrupts();
295 }
296
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800297 void operator()() {
298 ::aos::SetCurrentThreadName("SensorReader");
299
300 my_pid_ = getpid();
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800301
302 dma_synchronizer_->Start();
303
Austin Schuh8347cb62017-04-08 14:37:34 -0700304 ::aos::time::PhasedLoop phased_loop(last_period_,
305 ::std::chrono::milliseconds(3));
306 chrono::nanoseconds filtered_period = last_period_;
307
308 ::std::thread pwm_detecter_thread(
309 ::std::bind(&SensorReader::RunPWMDetecter, this));
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800310
311 ::aos::SetCurrentThreadRealtimePriority(40);
312 while (run_) {
313 {
314 const int iterations = phased_loop.SleepUntilNext();
315 if (iterations != 1) {
316 LOG(WARNING, "SensorReader skipped %d iterations\n", iterations - 1);
317 }
318 }
319 RunIteration();
Austin Schuh8347cb62017-04-08 14:37:34 -0700320
321 monotonic_clock::time_point last_tick_timepoint;
322 chrono::nanoseconds period;
323 {
324 ::std::unique_lock<::aos::stl_mutex> locker(tick_time_mutex_);
325 last_tick_timepoint = last_tick_time_monotonic_timepoint_;
326 period = last_period_;
327 }
328
329 if (last_tick_timepoint == monotonic_clock::min_time) {
330 continue;
331 }
332 chrono::nanoseconds new_offset = phased_loop.OffsetFromIntervalAndTime(
333 period, last_tick_timepoint + chrono::microseconds(2050));
334
335 // TODO(austin): If this is the first edge in a while, skip to it (plus
336 // an offset). Otherwise, slowly drift time to line up.
337
338 phased_loop.set_interval_and_offset(period, new_offset);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800339 }
Austin Schuh8347cb62017-04-08 14:37:34 -0700340 pwm_detecter_thread.join();
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800341 }
342
343 void RunIteration() {
Austin Schuh94f51e92017-10-30 19:25:32 -0700344 ::frc971::wpilib::SendRobotState(my_pid_);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800345
346 const auto values = constants::GetValues();
347
348 {
349 auto drivetrain_message = drivetrain_queue.position.MakeMessage();
350 drivetrain_message->right_encoder =
351 drivetrain_translate(drivetrain_right_encoder_->GetRaw());
Austin Schuh0fc1e6d2017-02-21 02:04:10 -0800352 drivetrain_message->right_speed =
353 drivetrain_velocity_translate(drivetrain_right_encoder_->GetPeriod());
354
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800355 drivetrain_message->left_encoder =
356 -drivetrain_translate(drivetrain_left_encoder_->GetRaw());
357 drivetrain_message->left_speed =
358 drivetrain_velocity_translate(drivetrain_left_encoder_->GetPeriod());
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800359
360 drivetrain_message.Send();
361 }
362
363 dma_synchronizer_->RunIteration();
364
365 {
366 auto superstructure_message = superstructure_queue.position.MakeMessage();
Brian Silverman052e69d2017-02-12 16:19:55 -0800367 CopyPosition(intake_encoder_, &superstructure_message->intake,
Brian Silverman50826c02017-02-18 14:40:25 -0800368 Values::kIntakeEncoderCountsPerRevolution,
Austin Schuh0fc1e6d2017-02-21 02:04:10 -0800369 Values::kIntakeEncoderRatio, intake_pot_translate, true,
Brian Silverman052e69d2017-02-12 16:19:55 -0800370 values.intake.pot_offset);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800371
Brianef030df2017-03-05 15:06:04 -0800372 CopyPosition(indexer_counter_, &superstructure_message->column.indexer,
373 Values::kIndexerEncoderCountsPerRevolution,
Austin Schuh546a0382017-04-16 19:10:18 -0700374 Values::kIndexerEncoderRatio, true);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800375
Brian Silverman50826c02017-02-18 14:40:25 -0800376 superstructure_message->theta_shooter =
377 encoder_translate(shooter_encoder_->GetRaw(),
378 Values::kShooterEncoderCountsPerRevolution,
379 Values::kShooterEncoderRatio);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800380
Brian Silverman50826c02017-02-18 14:40:25 -0800381 CopyPosition(hood_encoder_, &superstructure_message->hood,
382 Values::kHoodEncoderCountsPerRevolution,
Austin Schuh0fc1e6d2017-02-21 02:04:10 -0800383 Values::kHoodEncoderRatio, true);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800384
Brianef030df2017-03-05 15:06:04 -0800385 CopyPosition(turret_counter_, &superstructure_message->column.turret,
Brian Silverman50826c02017-02-18 14:40:25 -0800386 Values::kTurretEncoderCountsPerRevolution,
Austin Schuhd5ccb862017-03-11 22:06:36 -0800387 Values::kTurretEncoderRatio, false);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800388
389 superstructure_message.Send();
390 }
391
392 {
Philipp Schrader996a2a22017-02-22 05:02:48 +0000393 auto auto_mode_message = ::frc971::autonomous::auto_mode.MakeMessage();
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800394 auto_mode_message->mode = 0;
395 for (size_t i = 0; i < autonomous_modes_.size(); ++i) {
Austin Schuh8347cb62017-04-08 14:37:34 -0700396 if (autonomous_modes_[i] && autonomous_modes_[i]->Get()) {
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800397 auto_mode_message->mode |= 1 << i;
398 }
399 }
400 LOG_STRUCT(DEBUG, "auto mode", *auto_mode_message);
401 auto_mode_message.Send();
402 }
403 }
404
405 void Quit() { run_ = false; }
406
407 private:
Brian Silverman50826c02017-02-18 14:40:25 -0800408 double encoder_translate(int32_t value, double counts_per_revolution,
409 double ratio) {
410 return static_cast<double>(value) / counts_per_revolution * ratio *
411 (2.0 * M_PI);
412 }
413
Brian Silverman7cce2d32017-02-19 21:48:48 -0800414 void CopyPosition(const ::frc971::wpilib::DMAEncoder &encoder,
415 ::frc971::IndexPosition *position,
Brian Silverman50826c02017-02-18 14:40:25 -0800416 double encoder_counts_per_revolution, double encoder_ratio,
Brian Silverman7cce2d32017-02-19 21:48:48 -0800417 bool reverse) {
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800418 const double multiplier = reverse ? -1.0 : 1.0;
419 position->encoder =
Brian Silverman50826c02017-02-18 14:40:25 -0800420 multiplier * encoder_translate(encoder.polled_encoder_value(),
421 encoder_counts_per_revolution,
422 encoder_ratio);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800423 position->latched_encoder =
Brian Silverman50826c02017-02-18 14:40:25 -0800424 multiplier * encoder_translate(encoder.last_encoder_value(),
425 encoder_counts_per_revolution,
426 encoder_ratio);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800427 position->index_pulses = encoder.index_posedge_count();
428 }
429
Austin Schuh2a3e0632018-02-19 16:24:49 -0800430 void CopyPosition(
431 const ::frc971::wpilib::AbsoluteEncoderAndPotentiometer &encoder,
432 ::frc971::PotAndAbsolutePosition *position,
433 double encoder_counts_per_revolution, double encoder_ratio,
434 ::std::function<double(double)> potentiometer_translate, bool reverse,
435 double pot_offset) {
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800436 const double multiplier = reverse ? -1.0 : 1.0;
437 position->pot = multiplier * potentiometer_translate(
Brian Silverman50826c02017-02-18 14:40:25 -0800438 encoder.ReadPotentiometerVoltage()) +
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800439 pot_offset;
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800440 position->encoder =
Brian Silverman50826c02017-02-18 14:40:25 -0800441 multiplier * encoder_translate(encoder.ReadRelativeEncoder(),
442 encoder_counts_per_revolution,
443 encoder_ratio);
Austin Schuh0fc1e6d2017-02-21 02:04:10 -0800444
445 position->absolute_encoder =
446 (reverse ? (1.0 - encoder.ReadAbsoluteEncoder())
447 : encoder.ReadAbsoluteEncoder()) *
448 encoder_ratio * (2.0 * M_PI);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800449 }
450
Brianef030df2017-03-05 15:06:04 -0800451 void CopyPosition(const ::frc971::wpilib::DMAEdgeCounter &counter,
452 ::frc971::HallEffectAndPosition *position,
453 double encoder_counts_per_revolution, double encoder_ratio,
454 bool reverse) {
455 const double multiplier = reverse ? -1.0 : 1.0;
456 position->position =
457 multiplier * encoder_translate(counter.polled_encoder(),
458 encoder_counts_per_revolution,
459 encoder_ratio);
460 position->current = !counter.polled_value();
461 position->posedge_count = counter.negative_count();
462 position->negedge_count = counter.positive_count();
463 position->posedge_value =
464 multiplier * encoder_translate(counter.last_negative_encoder_value(),
465 encoder_counts_per_revolution,
466 encoder_ratio);
467 position->negedge_value =
468 multiplier * encoder_translate(counter.last_positive_encoder_value(),
469 encoder_counts_per_revolution,
470 encoder_ratio);
471 }
472
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800473 int32_t my_pid_;
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800474
Austin Schuh8347cb62017-04-08 14:37:34 -0700475 // Mutex to manage access to the period and tick time variables.
476 ::aos::stl_mutex tick_time_mutex_;
477 monotonic_clock::time_point last_tick_time_monotonic_timepoint_ =
478 monotonic_clock::min_time;
479 chrono::nanoseconds last_period_ = chrono::microseconds(5050);
480
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800481 ::std::unique_ptr<::frc971::wpilib::DMASynchronizer> dma_synchronizer_;
482
Brian Silverman052e69d2017-02-12 16:19:55 -0800483 DigitalGlitchFilter fast_encoder_filter_, medium_encoder_filter_,
Brianef030df2017-03-05 15:06:04 -0800484 hall_filter_;
Brian Silverman052e69d2017-02-12 16:19:55 -0800485
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800486 ::std::unique_ptr<Encoder> drivetrain_left_encoder_,
487 drivetrain_right_encoder_;
488
Austin Schuh2a3e0632018-02-19 16:24:49 -0800489 ::frc971::wpilib::AbsoluteEncoderAndPotentiometer intake_encoder_;
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800490
Brian Silverman052e69d2017-02-12 16:19:55 -0800491 ::std::unique_ptr<Encoder> indexer_encoder_;
Brianef030df2017-03-05 15:06:04 -0800492 ::std::unique_ptr<DigitalInput> indexer_hall_;
493 ::frc971::wpilib::DMAEdgeCounter indexer_counter_;
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800494
Brianef030df2017-03-05 15:06:04 -0800495 ::std::unique_ptr<Encoder> turret_encoder_;
496 ::std::unique_ptr<DigitalInput> turret_hall_;
497 ::frc971::wpilib::DMAEdgeCounter turret_counter_;
498
Brian Silverman7cce2d32017-02-19 21:48:48 -0800499 ::frc971::wpilib::DMAEncoder hood_encoder_;
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800500 ::std::unique_ptr<Encoder> shooter_encoder_;
501
Austin Schuh8347cb62017-04-08 14:37:34 -0700502 ::std::unique_ptr<DigitalInput> pwm_trigger_;
503
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800504 ::std::array<::std::unique_ptr<DigitalInput>, 4> autonomous_modes_;
505
506 ::std::atomic<bool> run_{true};
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800507};
508
Adam Snaidere0554ef2017-03-11 23:02:45 -0800509class SolenoidWriter {
510 public:
511 SolenoidWriter()
512 : superstructure_(".y2017.control_loops.superstructure_queue.output") {}
513
514 ::frc971::wpilib::BufferedPcm *pcm() { return &pcm_; }
515
Austin Schuh8347cb62017-04-08 14:37:34 -0700516 void set_lights(::std::unique_ptr<::frc971::wpilib::BufferedSolenoid> s) {
Adam Snaidere0554ef2017-03-11 23:02:45 -0800517 lights_ = ::std::move(s);
518 }
519
Austin Schuh8347cb62017-04-08 14:37:34 -0700520 void set_rgb_light(::std::unique_ptr<::frc971::wpilib::BufferedSolenoid> s) {
Austin Schuhc587c882017-03-29 21:33:10 -0700521 rgb_lights_ = ::std::move(s);
522 }
523
Adam Snaidere0554ef2017-03-11 23:02:45 -0800524 void operator()() {
525 ::aos::SetCurrentThreadName("Solenoids");
526 ::aos::SetCurrentThreadRealtimePriority(27);
527
528 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(20),
529 ::std::chrono::milliseconds(1));
530
531 while (run_) {
532 {
533 const int iterations = phased_loop.SleepUntilNext();
534 if (iterations != 1) {
535 LOG(DEBUG, "Solenoids skipped %d iterations\n", iterations - 1);
536 }
537 }
538
539 {
540 superstructure_.FetchLatest();
541 if (superstructure_.get()) {
542 LOG_STRUCT(DEBUG, "solenoids", *superstructure_);
543 lights_->Set(superstructure_->lights_on);
Austin Schuhc587c882017-03-29 21:33:10 -0700544 rgb_lights_->Set(superstructure_->red_light_on |
545 superstructure_->green_light_on |
546 superstructure_->blue_light_on);
Adam Snaidere0554ef2017-03-11 23:02:45 -0800547 }
548 }
549
550 pcm_.Flush();
551 }
552 }
553
554 void Quit() { run_ = false; }
555
556 private:
557 ::frc971::wpilib::BufferedPcm pcm_;
558
Austin Schuhc587c882017-03-29 21:33:10 -0700559 ::std::unique_ptr<::frc971::wpilib::BufferedSolenoid> lights_, rgb_lights_;
Adam Snaidere0554ef2017-03-11 23:02:45 -0800560
Austin Schuh8347cb62017-04-08 14:37:34 -0700561 ::aos::Queue<::y2017::control_loops::SuperstructureQueue::Output>
Adam Snaidere0554ef2017-03-11 23:02:45 -0800562 superstructure_;
563
564 ::std::atomic<bool> run_{true};
565};
566
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800567class DrivetrainWriter : public ::frc971::wpilib::LoopOutputHandler {
568 public:
Austin Schuh8347cb62017-04-08 14:37:34 -0700569 void set_drivetrain_left_victor(::std::unique_ptr<::frc::VictorSP> t) {
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800570 drivetrain_left_victor_ = ::std::move(t);
571 }
572
Austin Schuh8347cb62017-04-08 14:37:34 -0700573 void set_drivetrain_right_victor(::std::unique_ptr<::frc::VictorSP> t) {
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800574 drivetrain_right_victor_ = ::std::move(t);
575 }
576
577 private:
578 virtual void Read() override {
579 ::frc971::control_loops::drivetrain_queue.output.FetchAnother();
580 }
581
582 virtual void Write() override {
583 auto &queue = ::frc971::control_loops::drivetrain_queue.output;
584 LOG_STRUCT(DEBUG, "will output", *queue);
Austin Schuh410e3812017-02-21 16:44:03 -0800585 drivetrain_left_victor_->SetSpeed(-queue->left_voltage / 12.0);
586 drivetrain_right_victor_->SetSpeed(queue->right_voltage / 12.0);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800587 }
588
589 virtual void Stop() override {
590 LOG(WARNING, "drivetrain output too old\n");
591 drivetrain_left_victor_->SetDisabled();
592 drivetrain_right_victor_->SetDisabled();
593 }
594
Austin Schuh8347cb62017-04-08 14:37:34 -0700595 ::std::unique_ptr<::frc::VictorSP> drivetrain_left_victor_,
596 drivetrain_right_victor_;
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800597};
598
599class SuperstructureWriter : public ::frc971::wpilib::LoopOutputHandler {
600 public:
Austin Schuh8347cb62017-04-08 14:37:34 -0700601 void set_intake_victor(::std::unique_ptr<::frc::VictorSP> t) {
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800602 intake_victor_ = ::std::move(t);
603 }
Austin Schuh8347cb62017-04-08 14:37:34 -0700604 void set_intake_rollers_victor(::std::unique_ptr<::frc::VictorSP> t) {
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800605 intake_rollers_victor_ = ::std::move(t);
606 }
607
Austin Schuh8347cb62017-04-08 14:37:34 -0700608 void set_indexer_victor(::std::unique_ptr<::frc::VictorSP> t) {
Brian Silverman052e69d2017-02-12 16:19:55 -0800609 indexer_victor_ = ::std::move(t);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800610 }
Austin Schuh8347cb62017-04-08 14:37:34 -0700611 void set_indexer_roller_victor(::std::unique_ptr<::frc::VictorSP> t) {
Brian Silverman052e69d2017-02-12 16:19:55 -0800612 indexer_roller_victor_ = ::std::move(t);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800613 }
614
Austin Schuh6a8131b2017-04-08 15:39:22 -0700615 void set_gear_servo(::std::unique_ptr<::frc::Servo> t) {
616 gear_servo_ = ::std::move(t);
617 }
Austin Schuh8347cb62017-04-08 14:37:34 -0700618 void set_shooter_victor(::std::unique_ptr<::frc::VictorSP> t) {
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800619 shooter_victor_ = ::std::move(t);
620 }
Austin Schuh8347cb62017-04-08 14:37:34 -0700621 void set_turret_victor(::std::unique_ptr<::frc::VictorSP> t) {
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800622 turret_victor_ = ::std::move(t);
623 }
Austin Schuh8347cb62017-04-08 14:37:34 -0700624 void set_hood_victor(::std::unique_ptr<::frc::VictorSP> t) {
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800625 hood_victor_ = ::std::move(t);
626 }
627
Austin Schuhc587c882017-03-29 21:33:10 -0700628 void set_red_light(::std::unique_ptr<DigitalOutput> t) {
629 red_light_ = ::std::move(t);
630 }
631 void set_green_light(::std::unique_ptr<DigitalOutput> t) {
632 green_light_ = ::std::move(t);
633 }
634 void set_blue_light(::std::unique_ptr<DigitalOutput> t) {
635 blue_light_ = ::std::move(t);
636 }
637
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800638 private:
639 virtual void Read() override {
640 ::y2017::control_loops::superstructure_queue.output.FetchAnother();
641 }
642
643 virtual void Write() override {
644 auto &queue = ::y2017::control_loops::superstructure_queue.output;
645 LOG_STRUCT(DEBUG, "will output", *queue);
646 intake_victor_->SetSpeed(::aos::Clip(queue->voltage_intake,
647 -kMaxBringupPower, kMaxBringupPower) /
648 12.0);
649 intake_rollers_victor_->SetSpeed(queue->voltage_intake_rollers / 12.0);
Austin Schuhd5ccb862017-03-11 22:06:36 -0800650 indexer_victor_->SetSpeed(-queue->voltage_indexer / 12.0);
651 indexer_roller_victor_->SetSpeed(queue->voltage_indexer_rollers / 12.0);
Austin Schuh410e3812017-02-21 16:44:03 -0800652 turret_victor_->SetSpeed(::aos::Clip(-queue->voltage_turret,
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800653 -kMaxBringupPower, kMaxBringupPower) /
654 12.0);
655 hood_victor_->SetSpeed(
656 ::aos::Clip(queue->voltage_hood, -kMaxBringupPower, kMaxBringupPower) /
657 12.0);
658 shooter_victor_->SetSpeed(queue->voltage_shooter / 12.0);
Austin Schuhc587c882017-03-29 21:33:10 -0700659
660 red_light_->Set(queue->red_light_on);
661 green_light_->Set(queue->green_light_on);
662 blue_light_->Set(queue->blue_light_on);
Austin Schuh6a8131b2017-04-08 15:39:22 -0700663
664 gear_servo_->Set(queue->gear_servo);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800665 }
666
667 virtual void Stop() override {
668 LOG(WARNING, "Superstructure output too old.\n");
669 intake_victor_->SetDisabled();
670 intake_rollers_victor_->SetDisabled();
Brian Silverman052e69d2017-02-12 16:19:55 -0800671 indexer_victor_->SetDisabled();
672 indexer_roller_victor_->SetDisabled();
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800673 turret_victor_->SetDisabled();
674 hood_victor_->SetDisabled();
675 shooter_victor_->SetDisabled();
Austin Schuhc587c882017-03-29 21:33:10 -0700676
Austin Schuh6a8131b2017-04-08 15:39:22 -0700677 gear_servo_->SetOffline();
678
Austin Schuhc587c882017-03-29 21:33:10 -0700679 red_light_->Set(true);
680 green_light_->Set(true);
681 blue_light_->Set(true);
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800682 }
683
Austin Schuh8347cb62017-04-08 14:37:34 -0700684 ::std::unique_ptr<::frc::VictorSP> intake_victor_, intake_rollers_victor_,
685 indexer_victor_, indexer_roller_victor_, shooter_victor_, turret_victor_,
686 hood_victor_;
Austin Schuhc587c882017-03-29 21:33:10 -0700687
Austin Schuh6a8131b2017-04-08 15:39:22 -0700688 ::std::unique_ptr<::frc::Servo> gear_servo_;
689
Austin Schuhc587c882017-03-29 21:33:10 -0700690 ::std::unique_ptr<DigitalOutput> red_light_, green_light_, blue_light_;
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800691};
692
693class WPILibRobot : public ::frc971::wpilib::WPILibRobotBase {
694 public:
695 ::std::unique_ptr<Encoder> make_encoder(int index) {
696 return make_unique<Encoder>(10 + index * 2, 11 + index * 2, false,
697 Encoder::k4X);
698 }
699
700 void Run() override {
701 ::aos::InitNRT();
702 ::aos::SetCurrentThreadName("StartCompetition");
703
704 ::frc971::wpilib::JoystickSender joystick_sender;
705 ::std::thread joystick_thread(::std::ref(joystick_sender));
706
707 ::frc971::wpilib::PDPFetcher pdp_fetcher;
708 ::std::thread pdp_fetcher_thread(::std::ref(pdp_fetcher));
709 SensorReader reader;
710
711 // TODO(campbell): Update port numbers
712 reader.set_drivetrain_left_encoder(make_encoder(0));
713 reader.set_drivetrain_right_encoder(make_encoder(1));
714
Austin Schuh0fc1e6d2017-02-21 02:04:10 -0800715 reader.set_intake_encoder(make_encoder(3));
Brian Silverman50826c02017-02-18 14:40:25 -0800716 reader.set_intake_absolute(make_unique<DigitalInput>(0));
Austin Schuh0fc1e6d2017-02-21 02:04:10 -0800717 reader.set_intake_potentiometer(make_unique<AnalogInput>(4));
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800718
Austin Schuh0fc1e6d2017-02-21 02:04:10 -0800719 reader.set_indexer_encoder(make_encoder(5));
Brianef030df2017-03-05 15:06:04 -0800720 reader.set_indexer_hall(make_unique<DigitalInput>(4));
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800721
Austin Schuh0fc1e6d2017-02-21 02:04:10 -0800722 reader.set_turret_encoder(make_encoder(6));
Brianef030df2017-03-05 15:06:04 -0800723 reader.set_turret_hall(make_unique<DigitalInput>(2));
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800724
Austin Schuh0fc1e6d2017-02-21 02:04:10 -0800725 reader.set_hood_encoder(make_encoder(4));
726 reader.set_hood_index(make_unique<DigitalInput>(1));
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800727
Austin Schuh0fc1e6d2017-02-21 02:04:10 -0800728 reader.set_shooter_encoder(make_encoder(2));
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800729
Austin Schuh0fc1e6d2017-02-21 02:04:10 -0800730 reader.set_autonomous_mode(0, make_unique<DigitalInput>(9));
731 reader.set_autonomous_mode(1, make_unique<DigitalInput>(8));
Austin Schuh8347cb62017-04-08 14:37:34 -0700732
733 reader.set_pwm_trigger(make_unique<DigitalInput>(7));
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800734
735 reader.set_dma(make_unique<DMA>());
736 ::std::thread reader_thread(::std::ref(reader));
737
Brian Silvermanb4439852017-02-24 19:49:09 -0800738 auto imu_trigger = make_unique<DigitalInput>(3);
Austin Schuh0fc1e6d2017-02-21 02:04:10 -0800739 ::frc971::wpilib::ADIS16448 imu(SPI::Port::kOnboardCS1, imu_trigger.get());
Brian Silvermana70994f2017-03-16 22:32:55 -0700740 imu.SetDummySPI(SPI::Port::kOnboardCS2);
741 auto imu_reset = make_unique<DigitalOutput>(6);
742 imu.set_reset(imu_reset.get());
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800743 ::std::thread imu_thread(::std::ref(imu));
744
745 DrivetrainWriter drivetrain_writer;
746 drivetrain_writer.set_drivetrain_left_victor(
Austin Schuh8347cb62017-04-08 14:37:34 -0700747 ::std::unique_ptr<::frc::VictorSP>(new ::frc::VictorSP(7)));
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800748 drivetrain_writer.set_drivetrain_right_victor(
Austin Schuh8347cb62017-04-08 14:37:34 -0700749 ::std::unique_ptr<::frc::VictorSP>(new ::frc::VictorSP(3)));
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800750 ::std::thread drivetrain_writer_thread(::std::ref(drivetrain_writer));
751
752 SuperstructureWriter superstructure_writer;
753 superstructure_writer.set_intake_victor(
Austin Schuh8347cb62017-04-08 14:37:34 -0700754 ::std::unique_ptr<::frc::VictorSP>(new ::frc::VictorSP(1)));
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800755 superstructure_writer.set_intake_rollers_victor(
Austin Schuh8347cb62017-04-08 14:37:34 -0700756 ::std::unique_ptr<::frc::VictorSP>(new ::frc::VictorSP(4)));
Austin Schuh0fc1e6d2017-02-21 02:04:10 -0800757 superstructure_writer.set_indexer_victor(
Austin Schuh8347cb62017-04-08 14:37:34 -0700758 ::std::unique_ptr<::frc::VictorSP>(new ::frc::VictorSP(6)));
Brian Silverman052e69d2017-02-12 16:19:55 -0800759 superstructure_writer.set_indexer_roller_victor(
Austin Schuh8347cb62017-04-08 14:37:34 -0700760 ::std::unique_ptr<::frc::VictorSP>(new ::frc::VictorSP(5)));
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800761 superstructure_writer.set_turret_victor(
Austin Schuh8347cb62017-04-08 14:37:34 -0700762 ::std::unique_ptr<::frc::VictorSP>(new ::frc::VictorSP(9)));
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800763 superstructure_writer.set_hood_victor(
Austin Schuh8347cb62017-04-08 14:37:34 -0700764 ::std::unique_ptr<::frc::VictorSP>(new ::frc::VictorSP(2)));
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800765 superstructure_writer.set_shooter_victor(
Austin Schuh8347cb62017-04-08 14:37:34 -0700766 ::std::unique_ptr<::frc::VictorSP>(new ::frc::VictorSP(8)));
Austin Schuhc587c882017-03-29 21:33:10 -0700767
Austin Schuh6a8131b2017-04-08 15:39:22 -0700768 superstructure_writer.set_gear_servo(
769 ::std::unique_ptr<Servo>(new Servo(0)));
770
Austin Schuhc587c882017-03-29 21:33:10 -0700771 superstructure_writer.set_red_light(
772 ::std::unique_ptr<DigitalOutput>(new DigitalOutput(5)));
773 superstructure_writer.set_green_light(
774 ::std::unique_ptr<DigitalOutput>(new DigitalOutput(24)));
775 superstructure_writer.set_blue_light(
776 ::std::unique_ptr<DigitalOutput>(new DigitalOutput(25)));
777
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800778 ::std::thread superstructure_writer_thread(
779 ::std::ref(superstructure_writer));
780
Adam Snaidere0554ef2017-03-11 23:02:45 -0800781 SolenoidWriter solenoid_writer;
782 solenoid_writer.set_lights(solenoid_writer.pcm()->MakeSolenoid(0));
Austin Schuhc587c882017-03-29 21:33:10 -0700783 solenoid_writer.set_rgb_light(solenoid_writer.pcm()->MakeSolenoid(1));
Adam Snaidere0554ef2017-03-11 23:02:45 -0800784
785 ::std::thread solenoid_thread(::std::ref(solenoid_writer));
786
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800787 // Wait forever. Not much else to do...
788 while (true) {
789 const int r = select(0, nullptr, nullptr, nullptr, nullptr);
790 if (r != 0) {
791 PLOG(WARNING, "infinite select failed");
792 } else {
793 PLOG(WARNING, "infinite select succeeded??\n");
794 }
795 }
796
797 LOG(ERROR, "Exiting WPILibRobot\n");
798
799 joystick_sender.Quit();
800 joystick_thread.join();
801 pdp_fetcher.Quit();
802 pdp_fetcher_thread.join();
803 reader.Quit();
804 reader_thread.join();
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800805 imu.Quit();
806 imu_thread.join();
807
808 drivetrain_writer.Quit();
809 drivetrain_writer_thread.join();
810 superstructure_writer.Quit();
811 superstructure_writer_thread.join();
812
813 ::aos::Cleanup();
814 }
815};
816
Brian Silverman052e69d2017-02-12 16:19:55 -0800817} // namespace
Campbell Crowleyae6e8422017-02-05 12:38:50 -0800818} // namespace wpilib
819} // namespace y2017
820
821AOS_ROBOT_CLASS(::y2017::wpilib::WPILibRobot);