blob: 7bcf0bc52db69555b952763c2e9eeb191744d99b [file] [log] [blame]
Comran Morshed9a9948c2016-01-16 15:58:04 +00001#include <stdio.h>
2#include <string.h>
3#include <unistd.h>
4#include <inttypes.h>
5
6#include <thread>
7#include <mutex>
8#include <functional>
9
10#include "Encoder.h"
11#include "Talon.h"
12#include "DriverStation.h"
13#include "AnalogInput.h"
14#include "Compressor.h"
15#include "Relay.h"
16#include "frc971/wpilib/wpilib_robot_base.h"
17#include "dma.h"
18#ifndef WPILIB2015
19#include "DigitalGlitchFilter.h"
20#endif
21#undef ERROR
22
23#include "aos/common/logging/logging.h"
24#include "aos/common/logging/queue_logging.h"
25#include "aos/common/time.h"
26#include "aos/common/util/log_interval.h"
27#include "aos/common/util/phased_loop.h"
28#include "aos/common/util/wrapping_counter.h"
29#include "aos/common/stl_mutex.h"
30#include "aos/linux_code/init.h"
31#include "aos/common/messages/robot_state.q.h"
32
33#include "frc971/shifter_hall_effect.h"
34
35#include "frc971/control_loops/drivetrain/drivetrain.q.h"
Comran Morshed6c6a0a92016-01-17 12:45:16 +000036#include "y2016/constants.h"
Comran Morshed9a9948c2016-01-16 15:58:04 +000037
38#include "frc971/wpilib/joystick_sender.h"
39#include "frc971/wpilib/loop_output_handler.h"
40#include "frc971/wpilib/buffered_solenoid.h"
41#include "frc971/wpilib/buffered_pcm.h"
42#include "frc971/wpilib/gyro_sender.h"
43#include "frc971/wpilib/dma_edge_counting.h"
44#include "frc971/wpilib/interrupt_edge_counting.h"
45#include "frc971/wpilib/encoder_and_potentiometer.h"
46#include "frc971/wpilib/logging.q.h"
47#include "frc971/wpilib/wpilib_interface.h"
48#include "frc971/wpilib/pdp_fetcher.h"
49
50#ifndef M_PI
51#define M_PI 3.14159265358979323846
52#endif
53
54using ::frc971::control_loops::drivetrain_queue;
Comran Morshed9a9948c2016-01-16 15:58:04 +000055
Comran Morshed6c6a0a92016-01-17 12:45:16 +000056namespace y2016 {
Comran Morshed9a9948c2016-01-16 15:58:04 +000057namespace wpilib {
58
59// TODO(Brian): Fix the interpretation of the result of GetRaw here and in the
60// DMA stuff and then removing the * 2.0 in *_translate.
61// The low bit is direction.
62
63// TODO(brian): Replace this with ::std::make_unique once all our toolchains
64// have support.
65template <class T, class... U>
66std::unique_ptr<T> make_unique(U &&... u) {
67 return std::unique_ptr<T>(new T(std::forward<U>(u)...));
68}
69
70double drivetrain_translate(int32_t in) {
Comran Morshed6c6a0a92016-01-17 12:45:16 +000071 return -static_cast<double>(in) / (256.0 /*cpr*/ * 4.0 /*4x*/) *
Comran Morshed9a9948c2016-01-16 15:58:04 +000072 constants::GetValues().drivetrain_encoder_ratio *
73 (3.5 /*wheel diameter*/ * 2.54 / 100.0 * M_PI) * 2.0 / 2.0;
74}
75
76double drivetrain_velocity_translate(double in) {
77 return (1.0 / in) / 256.0 /*cpr*/ *
78 constants::GetValues().drivetrain_encoder_ratio *
79 (3.5 /*wheel diameter*/ * 2.54 / 100.0 * M_PI) * 2.0 / 2.0;
80}
81
82float hall_translate(const constants::ShifterHallEffect &k, float in_low,
83 float in_high) {
84 const float low_ratio =
85 0.5 * (in_low - static_cast<float>(k.low_gear_low)) /
86 static_cast<float>(k.low_gear_middle - k.low_gear_low);
87 const float high_ratio =
Comran Morshed6c6a0a92016-01-17 12:45:16 +000088 0.5 +
89 0.5 * (in_high - static_cast<float>(k.high_gear_middle)) /
90 static_cast<float>(k.high_gear_high - k.high_gear_middle);
Comran Morshed9a9948c2016-01-16 15:58:04 +000091
92 // Return low when we are below 1/2, and high when we are above 1/2.
93 if (low_ratio + high_ratio < 1.0) {
94 return low_ratio;
95 } else {
96 return high_ratio;
97 }
98}
99
Comran Morshed6c6a0a92016-01-17 12:45:16 +0000100// TODO(constants): Update.
Comran Morshed9a9948c2016-01-16 15:58:04 +0000101static const double kMaximumEncoderPulsesPerSecond =
102 5600.0 /* free speed RPM */ * 14.0 / 48.0 /* bottom gear reduction */ *
Comran Morshed6c6a0a92016-01-17 12:45:16 +0000103 18.0 / 32.0 /* big belt reduction */ * 18.0 /
104 66.0 /* top gear reduction */ * 48.0 / 18.0 /* encoder gears */ /
Comran Morshed9a9948c2016-01-16 15:58:04 +0000105 60.0 /* seconds / minute */ * 256.0 /* CPR */;
106
107class SensorReader {
108 public:
109 SensorReader() {
110 // Set it to filter out anything shorter than 1/4 of the minimum pulse width
111 // we should ever see.
112 encoder_filter_.SetPeriodNanoSeconds(
113 static_cast<int>(1 / 4.0 / kMaximumEncoderPulsesPerSecond * 1e9 + 0.5));
114 hall_filter_.SetPeriodNanoSeconds(100000);
115 }
116
Comran Morshed9a9948c2016-01-16 15:58:04 +0000117 void set_drivetrain_left_encoder(::std::unique_ptr<Encoder> encoder) {
118 drivetrain_left_encoder_ = ::std::move(encoder);
119 drivetrain_left_encoder_->SetMaxPeriod(0.005);
120 }
121
122 void set_drivetrain_right_encoder(::std::unique_ptr<Encoder> encoder) {
123 drivetrain_right_encoder_ = ::std::move(encoder);
124 drivetrain_right_encoder_->SetMaxPeriod(0.005);
125 }
126
127 void set_high_left_drive_hall(::std::unique_ptr<AnalogInput> analog) {
128 high_left_drive_hall_ = ::std::move(analog);
129 }
130
131 void set_low_right_drive_hall(::std::unique_ptr<AnalogInput> analog) {
132 low_right_drive_hall_ = ::std::move(analog);
133 }
134
135 void set_high_right_drive_hall(::std::unique_ptr<AnalogInput> analog) {
136 high_right_drive_hall_ = ::std::move(analog);
137 }
138
139 void set_low_left_drive_hall(::std::unique_ptr<AnalogInput> analog) {
140 low_left_drive_hall_ = ::std::move(analog);
141 }
142
Comran Morshed9a9948c2016-01-16 15:58:04 +0000143 // All of the DMA-related set_* calls must be made before this, and it doesn't
144 // hurt to do all of them.
Comran Morshed9a9948c2016-01-16 15:58:04 +0000145
Comran Morshed6c6a0a92016-01-17 12:45:16 +0000146 // TODO(comran): Add 2016 things down below for dma synchronization.
147 void set_dma(::std::unique_ptr<DMA> dma) {
Comran Morshed9a9948c2016-01-16 15:58:04 +0000148 dma_synchronizer_.reset(
149 new ::frc971::wpilib::DMASynchronizer(::std::move(dma)));
Comran Morshed9a9948c2016-01-16 15:58:04 +0000150 }
151
152 void operator()() {
153 ::aos::SetCurrentThreadName("SensorReader");
154
155 my_pid_ = getpid();
156 ds_ =
157#ifdef WPILIB2015
158 DriverStation::GetInstance();
159#else
160 &DriverStation::GetInstance();
161#endif
162
Comran Morshed9a9948c2016-01-16 15:58:04 +0000163 dma_synchronizer_->Start();
164
165 ::aos::time::PhasedLoop phased_loop(::aos::time::Time::InMS(5),
166 ::aos::time::Time::InMS(4));
167
168 ::aos::SetCurrentThreadRealtimePriority(40);
169 while (run_) {
170 {
171 const int iterations = phased_loop.SleepUntilNext();
172 if (iterations != 1) {
173 LOG(WARNING, "SensorReader skipped %d iterations\n", iterations - 1);
174 }
175 }
176 RunIteration();
177 }
Comran Morshed9a9948c2016-01-16 15:58:04 +0000178 }
179
180 void RunIteration() {
181 ::frc971::wpilib::SendRobotState(my_pid_, ds_);
182
183 const auto &values = constants::GetValues();
184
185 {
186 auto drivetrain_message = drivetrain_queue.position.MakeMessage();
187 drivetrain_message->right_encoder =
188 drivetrain_translate(drivetrain_right_encoder_->GetRaw());
189 drivetrain_message->left_encoder =
190 -drivetrain_translate(drivetrain_left_encoder_->GetRaw());
191 drivetrain_message->left_speed =
192 drivetrain_velocity_translate(drivetrain_left_encoder_->GetPeriod());
193 drivetrain_message->right_speed =
194 drivetrain_velocity_translate(drivetrain_right_encoder_->GetPeriod());
195
196 drivetrain_message->low_left_hall = low_left_drive_hall_->GetVoltage();
197 drivetrain_message->high_left_hall = high_left_drive_hall_->GetVoltage();
198 drivetrain_message->left_shifter_position =
199 hall_translate(values.left_drive, drivetrain_message->low_left_hall,
200 drivetrain_message->high_left_hall);
201
202 drivetrain_message->low_right_hall = low_right_drive_hall_->GetVoltage();
203 drivetrain_message->high_right_hall =
204 high_right_drive_hall_->GetVoltage();
205 drivetrain_message->right_shifter_position =
206 hall_translate(values.right_drive, drivetrain_message->low_right_hall,
207 drivetrain_message->high_right_hall);
208
209 drivetrain_message.Send();
210 }
211
Comran Morshed9a9948c2016-01-16 15:58:04 +0000212 dma_synchronizer_->RunIteration();
Comran Morshed9a9948c2016-01-16 15:58:04 +0000213 }
214
215 void Quit() { run_ = false; }
216
217 private:
Comran Morshed9a9948c2016-01-16 15:58:04 +0000218 int32_t my_pid_;
219 DriverStation *ds_;
220
221 ::std::unique_ptr<::frc971::wpilib::DMASynchronizer> dma_synchronizer_;
222
Comran Morshed9a9948c2016-01-16 15:58:04 +0000223 ::std::unique_ptr<Encoder> drivetrain_left_encoder_;
224 ::std::unique_ptr<Encoder> drivetrain_right_encoder_;
225 ::std::unique_ptr<AnalogInput> low_left_drive_hall_;
226 ::std::unique_ptr<AnalogInput> high_left_drive_hall_;
227 ::std::unique_ptr<AnalogInput> low_right_drive_hall_;
228 ::std::unique_ptr<AnalogInput> high_right_drive_hall_;
229
Comran Morshed9a9948c2016-01-16 15:58:04 +0000230 ::std::atomic<bool> run_{true};
231 DigitalGlitchFilter encoder_filter_, hall_filter_;
232};
233
234class SolenoidWriter {
235 public:
236 SolenoidWriter(const ::std::unique_ptr<::frc971::wpilib::BufferedPcm> &pcm)
237 : pcm_(pcm),
Comran Morshed9a9948c2016-01-16 15:58:04 +0000238 drivetrain_(".frc971.control_loops.drivetrain_queue.output") {}
239
240 void set_pressure_switch(::std::unique_ptr<DigitalInput> pressure_switch) {
241 pressure_switch_ = ::std::move(pressure_switch);
242 }
243
244 void set_compressor_relay(::std::unique_ptr<Relay> compressor_relay) {
245 compressor_relay_ = ::std::move(compressor_relay);
246 }
247
248 void set_drivetrain_left(
249 ::std::unique_ptr<::frc971::wpilib::BufferedSolenoid> s) {
250 drivetrain_left_ = ::std::move(s);
251 }
252
253 void set_drivetrain_right(
254 ::std::unique_ptr<::frc971::wpilib::BufferedSolenoid> s) {
255 drivetrain_right_ = ::std::move(s);
256 }
257
Comran Morshed9a9948c2016-01-16 15:58:04 +0000258 void operator()() {
259 ::aos::SetCurrentThreadName("Solenoids");
260 ::aos::SetCurrentThreadRealtimePriority(27);
261
262 ::aos::time::PhasedLoop phased_loop(::aos::time::Time::InMS(20),
263 ::aos::time::Time::InMS(1));
264
265 while (run_) {
266 {
267 const int iterations = phased_loop.SleepUntilNext();
268 if (iterations != 1) {
269 LOG(DEBUG, "Solenoids skipped %d iterations\n", iterations - 1);
270 }
271 }
272
273 {
Comran Morshed9a9948c2016-01-16 15:58:04 +0000274 drivetrain_.FetchLatest();
275 if (drivetrain_.get()) {
276 LOG_STRUCT(DEBUG, "solenoids", *drivetrain_);
277 drivetrain_left_->Set(!drivetrain_->left_high);
278 drivetrain_right_->Set(!drivetrain_->right_high);
279 }
280 }
281
282 {
283 ::frc971::wpilib::PneumaticsToLog to_log;
284 {
285 const bool compressor_on = !pressure_switch_->Get();
286 to_log.compressor_on = compressor_on;
287 if (compressor_on) {
288 compressor_relay_->Set(Relay::kForward);
289 } else {
290 compressor_relay_->Set(Relay::kOff);
291 }
292 }
293
294 pcm_->Flush();
295 to_log.read_solenoids = pcm_->GetAll();
296 LOG_STRUCT(DEBUG, "pneumatics info", to_log);
297 }
298 }
299 }
300
301 void Quit() { run_ = false; }
302
303 private:
304 const ::std::unique_ptr<::frc971::wpilib::BufferedPcm> &pcm_;
305
306 ::std::unique_ptr<::frc971::wpilib::BufferedSolenoid> drivetrain_left_;
307 ::std::unique_ptr<::frc971::wpilib::BufferedSolenoid> drivetrain_right_;
Comran Morshed9a9948c2016-01-16 15:58:04 +0000308
309 ::std::unique_ptr<DigitalInput> pressure_switch_;
310 ::std::unique_ptr<Relay> compressor_relay_;
311
Comran Morshed9a9948c2016-01-16 15:58:04 +0000312 ::aos::Queue<::frc971::control_loops::DrivetrainQueue::Output> drivetrain_;
313
314 ::std::atomic<bool> run_{true};
315};
316
317class DrivetrainWriter : public ::frc971::wpilib::LoopOutputHandler {
318 public:
319 void set_left_drivetrain_talon(::std::unique_ptr<Talon> t) {
320 left_drivetrain_talon_ = ::std::move(t);
321 }
322
323 void set_right_drivetrain_talon(::std::unique_ptr<Talon> t) {
324 right_drivetrain_talon_ = ::std::move(t);
325 }
326
327 private:
328 virtual void Read() override {
329 ::frc971::control_loops::drivetrain_queue.output.FetchAnother();
330 }
331
332 virtual void Write() override {
333 auto &queue = ::frc971::control_loops::drivetrain_queue.output;
334 LOG_STRUCT(DEBUG, "will output", *queue);
335 left_drivetrain_talon_->Set(-queue->left_voltage / 12.0);
336 right_drivetrain_talon_->Set(queue->right_voltage / 12.0);
337 }
338
339 virtual void Stop() override {
340 LOG(WARNING, "drivetrain output too old\n");
341 left_drivetrain_talon_->Disable();
342 right_drivetrain_talon_->Disable();
343 }
344
345 ::std::unique_ptr<Talon> left_drivetrain_talon_;
346 ::std::unique_ptr<Talon> right_drivetrain_talon_;
347};
348
Comran Morshed9a9948c2016-01-16 15:58:04 +0000349class WPILibRobot : public ::frc971::wpilib::WPILibRobotBase {
350 public:
351 ::std::unique_ptr<Encoder> make_encoder(int index) {
352 return make_unique<Encoder>(10 + index * 2, 11 + index * 2, false,
353 Encoder::k4X);
354 }
355
356 void Run() override {
357 ::aos::InitNRT();
358 ::aos::SetCurrentThreadName("StartCompetition");
359
360 ::frc971::wpilib::JoystickSender joystick_sender;
361 ::std::thread joystick_thread(::std::ref(joystick_sender));
362
363 ::frc971::wpilib::PDPFetcher pdp_fetcher;
364 ::std::thread pdp_fetcher_thread(::std::ref(pdp_fetcher));
365 SensorReader reader;
366
Comran Morshed6c6a0a92016-01-17 12:45:16 +0000367 // TODO(constants): Update these input numbers.
Comran Morshed9a9948c2016-01-16 15:58:04 +0000368 reader.set_drivetrain_left_encoder(make_encoder(0));
369 reader.set_drivetrain_right_encoder(make_encoder(1));
370 reader.set_high_left_drive_hall(make_unique<AnalogInput>(1));
371 reader.set_low_left_drive_hall(make_unique<AnalogInput>(0));
372 reader.set_high_right_drive_hall(make_unique<AnalogInput>(2));
373 reader.set_low_right_drive_hall(make_unique<AnalogInput>(3));
374
Comran Morshed9a9948c2016-01-16 15:58:04 +0000375 reader.set_dma(make_unique<DMA>());
376 ::std::thread reader_thread(::std::ref(reader));
377
378 ::frc971::wpilib::GyroSender gyro_sender;
379 ::std::thread gyro_thread(::std::ref(gyro_sender));
380
381 DrivetrainWriter drivetrain_writer;
382 drivetrain_writer.set_left_drivetrain_talon(
383 ::std::unique_ptr<Talon>(new Talon(5)));
384 drivetrain_writer.set_right_drivetrain_talon(
385 ::std::unique_ptr<Talon>(new Talon(2)));
386 ::std::thread drivetrain_writer_thread(::std::ref(drivetrain_writer));
387
Comran Morshed9a9948c2016-01-16 15:58:04 +0000388 ::std::unique_ptr<::frc971::wpilib::BufferedPcm> pcm(
389 new ::frc971::wpilib::BufferedPcm());
390 SolenoidWriter solenoid_writer(pcm);
391 solenoid_writer.set_drivetrain_left(pcm->MakeSolenoid(6));
392 solenoid_writer.set_drivetrain_right(pcm->MakeSolenoid(7));
Comran Morshed9a9948c2016-01-16 15:58:04 +0000393
394 solenoid_writer.set_pressure_switch(make_unique<DigitalInput>(25));
395 solenoid_writer.set_compressor_relay(make_unique<Relay>(0));
396 ::std::thread solenoid_thread(::std::ref(solenoid_writer));
397
398 // Wait forever. Not much else to do...
399 while (true) {
400 const int r = select(0, nullptr, nullptr, nullptr, nullptr);
401 if (r != 0) {
402 PLOG(WARNING, "infinite select failed");
403 } else {
404 PLOG(WARNING, "infinite select succeeded??\n");
405 }
406 }
407
408 LOG(ERROR, "Exiting WPILibRobot\n");
409
410 joystick_sender.Quit();
411 joystick_thread.join();
412 pdp_fetcher.Quit();
413 pdp_fetcher_thread.join();
414 reader.Quit();
415 reader_thread.join();
416 gyro_sender.Quit();
417 gyro_thread.join();
418
419 drivetrain_writer.Quit();
420 drivetrain_writer_thread.join();
Comran Morshed9a9948c2016-01-16 15:58:04 +0000421 solenoid_writer.Quit();
422 solenoid_thread.join();
423
424 ::aos::Cleanup();
425 }
426};
427
428} // namespace wpilib
Comran Morshed6c6a0a92016-01-17 12:45:16 +0000429} // namespace y2016
Comran Morshed9a9948c2016-01-16 15:58:04 +0000430
Comran Morshed6c6a0a92016-01-17 12:45:16 +0000431AOS_ROBOT_CLASS(::y2016::wpilib::WPILibRobot);