blob: 065494fecbc3e362be7d6b2553575f8dcf9a032d [file] [log] [blame]
Austin Schuhea9d6022017-01-02 13:38:07 -08001#include <inttypes.h>
2#include <stdio.h>
3#include <string.h>
4#include <unistd.h>
5
6#include <array>
7#include <functional>
8#include <mutex>
9#include <thread>
10
11#include "AnalogInput.h"
12#include "Compressor.h"
13#include "DigitalGlitchFilter.h"
14#include "DriverStation.h"
15#include "Encoder.h"
16#include "Relay.h"
17#include "Talon.h"
18#include "frc971/wpilib/wpilib_robot_base.h"
19#undef ERROR
20
21#include "aos/common/commonmath.h"
22#include "aos/common/logging/logging.h"
23#include "aos/common/logging/queue_logging.h"
24#include "aos/common/messages/robot_state.q.h"
25#include "aos/common/stl_mutex.h"
26#include "aos/common/time.h"
27#include "aos/common/util/log_interval.h"
28#include "aos/common/util/phased_loop.h"
29#include "aos/common/util/wrapping_counter.h"
30#include "aos/linux_code/init.h"
31
32#include "frc971/control_loops/control_loops.q.h"
33#include "frc971/control_loops/drivetrain/drivetrain.q.h"
34#include "y2016_bot4/control_loops/drivetrain/drivetrain_dog_motor_plant.h"
35
36#include "frc971/wpilib/gyro_sender.h"
37#include "frc971/wpilib/joystick_sender.h"
38#include "frc971/wpilib/logging.q.h"
39#include "frc971/wpilib/loop_output_handler.h"
40#include "frc971/wpilib/pdp_fetcher.h"
41#include "frc971/wpilib/wpilib_interface.h"
42
43#include "y2016_bot4/control_loops/drivetrain/drivetrain_base.h"
44
45#ifndef M_PI
46#define M_PI 3.14159265358979323846
47#endif
48
49using ::frc971::control_loops::drivetrain_queue;
50
51namespace y2016_bot4 {
52namespace wpilib {
53
54// TODO(brian): Replace this with ::std::make_unique once all our toolchains
55// have support.
56template <class T, class... U>
57std::unique_ptr<T> make_unique(U &&... u) {
58 return std::unique_ptr<T>(new T(std::forward<U>(u)...));
59}
60
61double drivetrain_translate(int32_t in) {
62 return -static_cast<double>(in) / (256.0 /*cpr*/ * 4.0 /*4x*/) *
63 ::y2016_bot4::constants::kDrivetrainEncoderRatio *
64 control_loops::drivetrain::kWheelRadius * 2.0 * M_PI;
65}
66
67double drivetrain_velocity_translate(double in) {
68 return (1.0 / in) / 256.0 /*cpr*/ *
69 ::y2016_bot4::constants::kDrivetrainEncoderRatio *
70 control_loops::drivetrain::kWheelRadius * 2.0 * M_PI;
71}
72
73constexpr double kMaxDrivetrainEncoderPulsesPerSecond =
74 5600.0 /* CIM free speed RPM */ * 12.0 / 54.0 *
75 60.0 /* seconds per minute */ * 256.0 /* CPR */ * 4 /* edges per cycle */;
76
77// Class to send position messages with sensor readings to our loops.
78class SensorReader {
79 public:
80 SensorReader() {
81 // Set it to filter out anything shorter than 1/4 of the minimum pulse width
82 // we should ever see.
83 drivetrain_encoder_filter_.SetPeriodNanoSeconds(
84 static_cast<int>(1 / 8.0 /* built-in tolerance */ /
85 kMaxDrivetrainEncoderPulsesPerSecond * 1e9 +
86 0.5));
87 }
88
89 // Drivetrain setters.
90 void set_drivetrain_left_encoder(::std::unique_ptr<Encoder> encoder) {
91 drivetrain_encoder_filter_.Add(encoder.get());
92 drivetrain_left_encoder_ = ::std::move(encoder);
93 }
94
95 void set_drivetrain_right_encoder(::std::unique_ptr<Encoder> encoder) {
96 drivetrain_encoder_filter_.Add(encoder.get());
97 drivetrain_right_encoder_ = ::std::move(encoder);
98 }
99
100 void operator()() {
101 ::aos::SetCurrentThreadName("SensorReader");
102
103 my_pid_ = getpid();
104 ds_ = &DriverStation::GetInstance();
105
106 ::aos::time::PhasedLoop phased_loop(::std::chrono::milliseconds(5),
107 ::std::chrono::milliseconds(0));
108
109 ::aos::SetCurrentThreadRealtimePriority(40);
110 while (run_) {
111 {
112 const int iterations = phased_loop.SleepUntilNext();
113 if (iterations != 1) {
114 LOG(WARNING, "SensorReader skipped %d iterations\n", iterations - 1);
115 }
116 }
117 RunIteration();
118 }
119 }
120
121 void RunIteration() {
122 ::frc971::wpilib::SendRobotState(my_pid_, ds_);
123
124 {
125 auto drivetrain_message = drivetrain_queue.position.MakeMessage();
126 drivetrain_message->right_encoder =
127 -drivetrain_translate(drivetrain_right_encoder_->GetRaw());
128 drivetrain_message->left_encoder =
129 drivetrain_translate(drivetrain_left_encoder_->GetRaw());
130 drivetrain_message->left_speed =
131 drivetrain_velocity_translate(drivetrain_left_encoder_->GetPeriod());
132 drivetrain_message->right_speed =
133 drivetrain_velocity_translate(drivetrain_right_encoder_->GetPeriod());
134
135 drivetrain_message.Send();
136 }
137 }
138
139 void Quit() { run_ = false; }
140
141 private:
142 int32_t my_pid_;
143 DriverStation *ds_;
144
145 ::std::unique_ptr<Encoder> drivetrain_left_encoder_,
146 drivetrain_right_encoder_;
147
148 ::std::atomic<bool> run_{true};
149 DigitalGlitchFilter drivetrain_encoder_filter_, intake_encoder_filter_;
150};
151
152class DrivetrainWriter : public ::frc971::wpilib::LoopOutputHandler {
153 public:
154 void set_drivetrain_left_talon(::std::unique_ptr<Talon> t0,
155 ::std::unique_ptr<Talon> t1) {
156 drivetrain_left_talon_0_ = ::std::move(t0);
157 drivetrain_left_talon_1_ = ::std::move(t1);
158 }
159
160 void set_drivetrain_right_talon(::std::unique_ptr<Talon> t0,
161 ::std::unique_ptr<Talon> t1) {
162 drivetrain_right_talon_0_ = ::std::move(t0);
163 drivetrain_right_talon_1_ = ::std::move(t1);
164 }
165
166 private:
167 virtual void Read() override {
168 ::frc971::control_loops::drivetrain_queue.output.FetchAnother();
169 }
170
171 virtual void Write() override {
172 auto &queue = ::frc971::control_loops::drivetrain_queue.output;
173 LOG_STRUCT(DEBUG, "will output", *queue);
Brian Silverman6eaa2d82017-02-04 20:48:30 -0800174 drivetrain_left_talon_0_->SetSpeed(-queue->left_voltage / 12.0);
175 drivetrain_left_talon_1_->SetSpeed(-queue->left_voltage / 12.0);
176 drivetrain_right_talon_0_->SetSpeed(queue->right_voltage / 12.0);
177 drivetrain_right_talon_1_->SetSpeed(queue->right_voltage / 12.0);
Austin Schuhea9d6022017-01-02 13:38:07 -0800178 }
179
180 virtual void Stop() override {
181 LOG(WARNING, "drivetrain output too old\n");
Brian Silverman6eaa2d82017-02-04 20:48:30 -0800182 drivetrain_left_talon_0_->SetDisabled();
183 drivetrain_right_talon_0_->SetDisabled();
184 drivetrain_left_talon_1_->SetDisabled();
185 drivetrain_right_talon_1_->SetDisabled();
Austin Schuhea9d6022017-01-02 13:38:07 -0800186 }
187
188 ::std::unique_ptr<Talon> drivetrain_left_talon_0_, drivetrain_right_talon_0_,
189 drivetrain_right_talon_1_, drivetrain_left_talon_1_;
190};
191
192class WPILibRobot : public ::frc971::wpilib::WPILibRobotBase {
193 public:
194 ::std::unique_ptr<Encoder> make_encoder(int index) {
195 return make_unique<Encoder>(10 + index * 2, 11 + index * 2, false,
196 Encoder::k4X);
197 }
198
199 void Run() override {
200 ::aos::InitNRT();
201 ::aos::SetCurrentThreadName("StartCompetition");
202
203 ::frc971::wpilib::JoystickSender joystick_sender;
204 ::std::thread joystick_thread(::std::ref(joystick_sender));
205
206 ::frc971::wpilib::PDPFetcher pdp_fetcher;
207 ::std::thread pdp_fetcher_thread(::std::ref(pdp_fetcher));
208 SensorReader reader;
209
210 reader.set_drivetrain_left_encoder(make_encoder(1));
211 reader.set_drivetrain_right_encoder(make_encoder(0));
212 ::std::thread reader_thread(::std::ref(reader));
213
214 ::frc971::wpilib::GyroSender gyro_sender;
215 ::std::thread gyro_thread(::std::ref(gyro_sender));
216
217 DrivetrainWriter drivetrain_writer;
218 drivetrain_writer.set_drivetrain_left_talon(
219 ::std::unique_ptr<Talon>(new Talon(0)),
220 ::std::unique_ptr<Talon>(new Talon(3)));
221 drivetrain_writer.set_drivetrain_right_talon(
222 ::std::unique_ptr<Talon>(new Talon(1)),
223 ::std::unique_ptr<Talon>(new Talon(2)));
224 ::std::thread drivetrain_writer_thread(::std::ref(drivetrain_writer));
225
226 // Wait forever. Not much else to do...
227 while (true) {
228 const int r = select(0, nullptr, nullptr, nullptr, nullptr);
229 if (r != 0) {
230 PLOG(WARNING, "infinite select failed");
231 } else {
232 PLOG(WARNING, "infinite select succeeded??\n");
233 }
234 }
235
236 LOG(ERROR, "Exiting WPILibRobot\n");
237
238 joystick_sender.Quit();
239 joystick_thread.join();
240 pdp_fetcher.Quit();
241 pdp_fetcher_thread.join();
242 reader.Quit();
243 reader_thread.join();
244 gyro_sender.Quit();
245 gyro_thread.join();
246
247 drivetrain_writer.Quit();
248 drivetrain_writer_thread.join();
249
250 ::aos::Cleanup();
251 }
252};
253
254} // namespace wpilib
255} // namespace y2016_bot4
256
257AOS_ROBOT_CLASS(::y2016_bot4::wpilib::WPILibRobot);