blob: 31623d098c7d016dc4ed2b87e14f88e78398d30a [file] [log] [blame]
Campbell Crowley71b5f132017-02-18 13:16:08 -08001#include <stdio.h>
2#include <string.h>
3#include <unistd.h>
4#include <math.h>
5
Austin Schuh3028b1d2017-03-11 22:12:13 -08006#include "aos/common/actions/actions.h"
Campbell Crowley71b5f132017-02-18 13:16:08 -08007#include "aos/common/input/driver_station_data.h"
8#include "aos/common/logging/logging.h"
Campbell Crowley71b5f132017-02-18 13:16:08 -08009#include "aos/common/time.h"
Austin Schuh3028b1d2017-03-11 22:12:13 -080010#include "aos/common/util/log_interval.h"
11#include "aos/input/joystick_input.h"
12#include "aos/linux_code/init.h"
Campbell Crowley71b5f132017-02-18 13:16:08 -080013#include "frc971/autonomous/auto.q.h"
Austin Schuh3028b1d2017-03-11 22:12:13 -080014#include "frc971/autonomous/base_autonomous_actor.h"
15#include "frc971/control_loops/drivetrain/drivetrain.q.h"
16#include "y2017/constants.h"
17#include "y2017/control_loops/superstructure/superstructure.q.h"
Campbell Crowley71b5f132017-02-18 13:16:08 -080018
19using ::frc971::control_loops::drivetrain_queue;
20using ::y2017::control_loops::superstructure_queue;
21
22using ::aos::input::driver_station::ButtonLocation;
23using ::aos::input::driver_station::ControlBit;
24using ::aos::input::driver_station::JoystickAxis;
25using ::aos::input::driver_station::POVLocation;
26
27namespace y2017 {
28namespace input {
29namespace joysticks {
30
Austin Schuh51b1bae2017-04-09 18:31:57 -070031// Keep the other versions around so we can switch quickly.
32//#define STEERINGWHEEL
33#define PISTOL
34//#define XBOX
35
36#ifdef STEERINGWHEEL
Campbell Crowley71b5f132017-02-18 13:16:08 -080037const JoystickAxis kSteeringWheel(1, 1), kDriveThrottle(2, 2);
38const ButtonLocation kQuickTurn(1, 5);
Campbell Crowley71b5f132017-02-18 13:16:08 -080039const ButtonLocation kTurn1(1, 7);
40const ButtonLocation kTurn2(1, 11);
41
Austin Schuh51b1bae2017-04-09 18:31:57 -070042#endif
43
44#ifdef PISTOL
45// Pistol Grip controller
46const JoystickAxis kSteeringWheel(1, 1), kDriveThrottle(1, 2);
47//const ButtonLocation kQuickTurn(1, 7);
48const ButtonLocation kQuickTurn(1, 8);
49
50// Nop
51//const ButtonLocation kTurn1(1, 8);
52const ButtonLocation kTurn2(1, 9);
53
54const ButtonLocation kTurn1(1, 7);
55#endif
56
57#ifdef XBOX
58// xbox
59const JoystickAxis kSteeringWheel(1, 5), kDriveThrottle(1, 2);
60const ButtonLocation kQuickTurn(1, 5);
61
62// Nop
63const ButtonLocation kTurn1(1, 1);
64const ButtonLocation kTurn2(1, 2);
65
66#endif
67
68
Austin Schuh55c8d302017-04-05 19:25:37 -070069const ButtonLocation kGearSlotBack(2, 11);
70
Campbell Crowley71b5f132017-02-18 13:16:08 -080071const ButtonLocation kIntakeDown(3, 9);
Austin Schuhd0629b12017-03-22 22:37:16 -070072const POVLocation kIntakeUp(3, 90);
Campbell Crowley71b5f132017-02-18 13:16:08 -080073const ButtonLocation kIntakeIn(3, 12);
74const ButtonLocation kIntakeOut(3, 8);
Campbell Crowley71b5f132017-02-18 13:16:08 -080075const ButtonLocation kFire(3, 3);
76const ButtonLocation kCloseShot(3, 7);
77const ButtonLocation kMiddleShot(3, 6);
78const POVLocation kFarShot(3, 270);
79
80const ButtonLocation kVisionAlign(3, 5);
81
82const ButtonLocation kReverseIndexer(3, 4);
83const ButtonLocation kExtra1(3, 11);
84const ButtonLocation kExtra2(3, 10);
Austin Schuhd0629b12017-03-22 22:37:16 -070085const ButtonLocation kHang(3, 2);
Campbell Crowley71b5f132017-02-18 13:16:08 -080086
87class Reader : public ::aos::input::JoystickInput {
88 public:
89 Reader() {}
90
Austin Schuhd0629b12017-03-22 22:37:16 -070091 enum class ShotDistance { CLOSE_SHOT, MIDDLE_SHOT, FAR_SHOT };
92
93 ShotDistance last_shot_distance_ = ShotDistance::FAR_SHOT;
94
Campbell Crowley71b5f132017-02-18 13:16:08 -080095 void RunIteration(const ::aos::input::driver_station::Data &data) override {
96 bool last_auto_running = auto_running_;
97 auto_running_ = data.GetControlBit(ControlBit::kAutonomous) &&
98 data.GetControlBit(ControlBit::kEnabled);
99 if (auto_running_ != last_auto_running) {
100 if (auto_running_) {
101 StartAuto();
102 } else {
103 StopAuto();
104 }
105 }
106
107 vision_valid_ = false;
108
109 if (!auto_running_) {
110 HandleDrivetrain(data);
111 HandleTeleop(data);
112 }
113
114 // Process any pending actions.
115 action_queue_.Tick();
116 was_running_ = action_queue_.Running();
117 }
Austin Schuhd0629b12017-03-22 22:37:16 -0700118 int intake_accumulator_ = 0;
Campbell Crowley71b5f132017-02-18 13:16:08 -0800119
Austin Schuh51b1bae2017-04-09 18:31:57 -0700120 double Deadband(double value, const double deadband) {
121 if (::std::abs(value) < deadband) {
122 value = 0.0;
123 } else if (value > 0.0) {
124 value = (value - deadband) / (1.0 - deadband);
125 } else {
126 value = (value + deadband) / (1.0 - deadband);
127 }
128 return value;
129 }
130
Campbell Crowley71b5f132017-02-18 13:16:08 -0800131 void HandleDrivetrain(const ::aos::input::driver_station::Data &data) {
132 bool is_control_loop_driving = false;
133
Austin Schuh51b1bae2017-04-09 18:31:57 -0700134#ifdef STEERINGWHEEL
Campbell Crowley71b5f132017-02-18 13:16:08 -0800135 const double wheel = -data.GetAxis(kSteeringWheel);
136 const double throttle = -data.GetAxis(kDriveThrottle);
Austin Schuh51b1bae2017-04-09 18:31:57 -0700137#endif
138
139#ifdef XBOX
140 // xbox
141 constexpr double kWheelDeadband = 0.05;
142 constexpr double kThrottleDeadband = 0.05;
143 const double wheel =
144 Deadband(-data.GetAxis(kSteeringWheel), kWheelDeadband);
145
146 const double unmodified_throttle =
147 Deadband(-data.GetAxis(kDriveThrottle), kThrottleDeadband);
148
149 // Apply a sin function that's scaled to make it feel better.
150 constexpr double throttle_range = M_PI_2 * 0.9;
151
152 double throttle = ::std::sin(throttle_range * unmodified_throttle) /
153 ::std::sin(throttle_range);
154 throttle =
155 ::std::sin(throttle_range * throttle) / ::std::sin(throttle_range);
156 throttle = 2.0 * unmodified_throttle - throttle;
157#endif
158
159#ifdef PISTOL
160 const double wheel = data.GetAxis(kSteeringWheel) / 0.488;
161
162 const double unscaled_throttle = -data.GetAxis(kDriveThrottle);
163 double unmodified_throttle;
164 if (unscaled_throttle < 0.0) {
165 unmodified_throttle = unscaled_throttle / 0.228;
166 } else {
167 unmodified_throttle = unscaled_throttle / 0.484;
168 }
169 unmodified_throttle = Deadband(unmodified_throttle, 0.1);
170
171 // Apply a sin function that's scaled to make it feel better.
172 constexpr double throttle_range = M_PI_2 * 0.5;
173
174 double throttle = ::std::sin(throttle_range * unmodified_throttle) /
175 ::std::sin(throttle_range);
176 throttle =
177 ::std::sin(throttle_range * throttle) / ::std::sin(throttle_range);
178 throttle = 2.0 * unmodified_throttle - throttle;
179#endif
180
Campbell Crowley71b5f132017-02-18 13:16:08 -0800181 drivetrain_queue.status.FetchLatest();
Austin Schuhd0629b12017-03-22 22:37:16 -0700182 if (drivetrain_queue.status.get()) {
183 robot_velocity_ = drivetrain_queue.status->robot_speed;
184 }
Campbell Crowley71b5f132017-02-18 13:16:08 -0800185
Austin Schuh55c8d302017-04-05 19:25:37 -0700186 if (data.PosEdge(kTurn1) || data.PosEdge(kTurn2) ||
187 data.PosEdge(kGearSlotBack)) {
Campbell Crowley71b5f132017-02-18 13:16:08 -0800188 if (drivetrain_queue.status.get()) {
189 left_goal_ = drivetrain_queue.status->estimated_left_position;
190 right_goal_ = drivetrain_queue.status->estimated_right_position;
191 }
192 }
Austin Schuh51b1bae2017-04-09 18:31:57 -0700193#ifdef PISTOL
194 double current_left_goal = left_goal_ - wheel * 0.20 + throttle * 0.3;
195 double current_right_goal = right_goal_ + wheel * 0.20 + throttle * 0.3;
196#else
Austin Schuh55c8d302017-04-05 19:25:37 -0700197 double current_left_goal = left_goal_ - wheel * 0.5 + throttle * 0.3;
198 double current_right_goal = right_goal_ + wheel * 0.5 + throttle * 0.3;
Austin Schuh51b1bae2017-04-09 18:31:57 -0700199#endif
Campbell Crowley71b5f132017-02-18 13:16:08 -0800200 if (data.IsPressed(kTurn1) || data.IsPressed(kTurn2)) {
201 is_control_loop_driving = true;
202 }
Austin Schuh55c8d302017-04-05 19:25:37 -0700203 if (data.IsPressed(kGearSlotBack)) {
204 is_control_loop_driving = true;
205 current_left_goal = left_goal_ - 0.03;
206 current_right_goal = right_goal_ - 0.03;
207 }
208 auto new_drivetrain_goal = drivetrain_queue.goal.MakeMessage();
209 new_drivetrain_goal->steering = wheel;
210 new_drivetrain_goal->throttle = throttle;
211 new_drivetrain_goal->quickturn = data.IsPressed(kQuickTurn);
212 new_drivetrain_goal->control_loop_driving = is_control_loop_driving;
213 new_drivetrain_goal->left_goal = current_left_goal;
214 new_drivetrain_goal->right_goal = current_right_goal;
215 new_drivetrain_goal->left_velocity_goal = 0;
216 new_drivetrain_goal->right_velocity_goal = 0;
217
218 new_drivetrain_goal->linear.max_velocity = 3.0;
219 new_drivetrain_goal->linear.max_acceleration = 20.0;
220
221 if (!new_drivetrain_goal.Send()) {
Campbell Crowley71b5f132017-02-18 13:16:08 -0800222 LOG(WARNING, "sending stick values failed\n");
223 }
224 }
225
226 void HandleTeleop(const ::aos::input::driver_station::Data &data) {
227 // Default the intake to in.
Austin Schuhd0629b12017-03-22 22:37:16 -0700228 intake_goal_ = 0.07;
Adam Snaidere0554ef2017-03-11 23:02:45 -0800229 bool lights_on = false;
Austin Schuhd0629b12017-03-22 22:37:16 -0700230 bool vision_track = false;
Campbell Crowley71b5f132017-02-18 13:16:08 -0800231
232 if (!data.GetControlBit(ControlBit::kEnabled)) {
233 action_queue_.CancelAllActions();
234 LOG(DEBUG, "Canceling\n");
235 }
236
237 superstructure_queue.status.FetchLatest();
238 if (!superstructure_queue.status.get()) {
239 LOG(ERROR, "Got no superstructure status packet.\n");
240 return;
241 }
242
Austin Schuhd0629b12017-03-22 22:37:16 -0700243 if (data.IsPressed(kIntakeUp)) {
244 intake_goal_ = 0.0;
245 turret_goal_ = 0.0;
246 }
Austin Schuh405724e2017-04-09 18:34:18 -0700247 if (data.IsPressed(kIntakeDown)) {
248 intake_goal_ = 0.235;
249 // Don't go quite so far out since we have a gear mech out now.
250 if (data.IsPressed(kIntakeUp)) {
251 intake_goal_ = 0.160;
252 }
253 }
Austin Schuhd0629b12017-03-22 22:37:16 -0700254
Campbell Crowley71b5f132017-02-18 13:16:08 -0800255
256 if (data.IsPressed(kVisionAlign)) {
257 // Align shot using vision
258 // TODO(campbell): Add vision aligning.
Adam Snaidere0554ef2017-03-11 23:02:45 -0800259 lights_on = true;
Austin Schuhd0629b12017-03-22 22:37:16 -0700260 vision_track = true;
261 }
262 if (data.PosEdge(kMiddleShot)) {
263 turret_goal_ = -M_PI;
264 }
Austin Schuh405724e2017-04-09 18:34:18 -0700265 if (data.PosEdge(kCloseShot)) {
266 turret_goal_ = -M_PI;
267 }
Austin Schuhd0629b12017-03-22 22:37:16 -0700268 if (data.PosEdge(kFarShot)) {
269 turret_goal_ = 0.0;
270 }
271
272 if (data.IsPressed(kCloseShot)) {
273 last_shot_distance_ = ShotDistance::CLOSE_SHOT;
Campbell Crowley71b5f132017-02-18 13:16:08 -0800274 } else if (data.IsPressed(kMiddleShot)) {
Austin Schuhd0629b12017-03-22 22:37:16 -0700275 last_shot_distance_ = ShotDistance::MIDDLE_SHOT;
Campbell Crowley71b5f132017-02-18 13:16:08 -0800276 } else if (data.IsPressed(kFarShot)) {
Austin Schuhd0629b12017-03-22 22:37:16 -0700277 last_shot_distance_ = ShotDistance::FAR_SHOT;
278 }
279
280 if (data.IsPressed(kVisionAlign) || data.IsPressed(kCloseShot) ||
281 data.IsPressed(kMiddleShot) || data.IsPressed(kFarShot) ||
282 data.IsPressed(kFire)) {
283 switch (last_shot_distance_) {
284 case ShotDistance::CLOSE_SHOT:
Austin Schuh405724e2017-04-09 18:34:18 -0700285 hood_goal_ = 0.30;
286 shooter_velocity_ = 322.0;
Austin Schuhd0629b12017-03-22 22:37:16 -0700287 break;
288 case ShotDistance::MIDDLE_SHOT:
Austin Schuh405724e2017-04-09 18:34:18 -0700289 hood_goal_ = 0.43 - 0.00;
290 shooter_velocity_ = 361.0;
Austin Schuhd0629b12017-03-22 22:37:16 -0700291 break;
292 case ShotDistance::FAR_SHOT:
Austin Schuh405724e2017-04-09 18:34:18 -0700293 hood_goal_ = 0.43 - 0.01;
294 shooter_velocity_ = 365.0;
Austin Schuhd0629b12017-03-22 22:37:16 -0700295 break;
296 }
Campbell Crowley71b5f132017-02-18 13:16:08 -0800297 } else {
Austin Schuhd0629b12017-03-22 22:37:16 -0700298 //hood_goal_ = 0.15;
Campbell Crowley71b5f132017-02-18 13:16:08 -0800299 shooter_velocity_ = 0.0;
300 }
301
302 if (data.IsPressed(kExtra1)) {
Austin Schuhd0629b12017-03-22 22:37:16 -0700303 //turret_goal_ = -M_PI * 3.0 / 4.0;
304 turret_goal_ += 0.150;
Campbell Crowley71b5f132017-02-18 13:16:08 -0800305 }
306 if (data.IsPressed(kExtra2)) {
Austin Schuhd0629b12017-03-22 22:37:16 -0700307 //turret_goal_ = M_PI * 3.0 / 4.0;
308 turret_goal_ -= 0.150;
Campbell Crowley71b5f132017-02-18 13:16:08 -0800309 }
Austin Schuhd0629b12017-03-22 22:37:16 -0700310 turret_goal_ = ::std::max(::std::min(turret_goal_, M_PI), -M_PI);
Campbell Crowley71b5f132017-02-18 13:16:08 -0800311
312 fire_ = data.IsPressed(kFire) && shooter_velocity_ != 0.0;
Austin Schuhd0629b12017-03-22 22:37:16 -0700313 if (data.IsPressed(kVisionAlign)) {
314 fire_ = fire_ && superstructure_queue.status->turret.vision_tracking;
315 }
Campbell Crowley71b5f132017-02-18 13:16:08 -0800316
317 auto new_superstructure_goal = superstructure_queue.goal.MakeMessage();
Austin Schuhd0629b12017-03-22 22:37:16 -0700318 if (data.IsPressed(kHang)) {
319 intake_goal_ = 0.23;
320 }
321
Campbell Crowley71b5f132017-02-18 13:16:08 -0800322 new_superstructure_goal->intake.distance = intake_goal_;
Austin Schuh3028b1d2017-03-11 22:12:13 -0800323 new_superstructure_goal->intake.disable_intake = false;
Campbell Crowley71b5f132017-02-18 13:16:08 -0800324 new_superstructure_goal->turret.angle = turret_goal_;
Austin Schuhd0629b12017-03-22 22:37:16 -0700325 new_superstructure_goal->turret.track = vision_track;
Campbell Crowley71b5f132017-02-18 13:16:08 -0800326 new_superstructure_goal->hood.angle = hood_goal_;
327 new_superstructure_goal->shooter.angular_velocity = shooter_velocity_;
328
Austin Schuh6a8131b2017-04-08 15:39:22 -0700329 if (data.IsPressed(kIntakeUp)) {
Austin Schuhd6fa5e02017-04-12 20:52:17 -0700330 new_superstructure_goal->intake.gear_servo = 0.30;
Austin Schuh6a8131b2017-04-08 15:39:22 -0700331 } else {
332 // Clamp the gear
Austin Schuhd6fa5e02017-04-12 20:52:17 -0700333 new_superstructure_goal->intake.gear_servo = 0.66;
Austin Schuh6a8131b2017-04-08 15:39:22 -0700334 }
335
Campbell Crowley71b5f132017-02-18 13:16:08 -0800336 new_superstructure_goal->intake.profile_params.max_velocity = 0.50;
Campbell Crowley71b5f132017-02-18 13:16:08 -0800337 new_superstructure_goal->hood.profile_params.max_velocity = 5.0;
338
339 new_superstructure_goal->intake.profile_params.max_acceleration = 5.0;
Austin Schuhd0629b12017-03-22 22:37:16 -0700340 if (vision_track) {
341 new_superstructure_goal->turret.profile_params.max_acceleration = 35.0;
342 new_superstructure_goal->turret.profile_params.max_velocity = 10.0;
343 } else {
344 new_superstructure_goal->turret.profile_params.max_acceleration = 15.0;
345 new_superstructure_goal->turret.profile_params.max_velocity = 6.0;
346 }
Campbell Crowley71b5f132017-02-18 13:16:08 -0800347 new_superstructure_goal->hood.profile_params.max_acceleration = 25.0;
348
Austin Schuh3028b1d2017-03-11 22:12:13 -0800349 new_superstructure_goal->intake.voltage_rollers = 0.0;
Adam Snaidere0554ef2017-03-11 23:02:45 -0800350 new_superstructure_goal->lights_on = lights_on;
Austin Schuh3028b1d2017-03-11 22:12:13 -0800351
Austin Schuh8e4a7ee2017-04-05 19:26:06 -0700352 if (superstructure_queue.status->intake.position >
353 superstructure_queue.status->intake.unprofiled_goal_position + 0.01) {
354 intake_accumulator_ = 10;
355 }
356 if (intake_accumulator_ > 0) {
357 --intake_accumulator_;
358 if (!superstructure_queue.status->intake.estopped) {
359 new_superstructure_goal->intake.voltage_rollers = 10.0;
360 }
361 }
362
Campbell Crowley71b5f132017-02-18 13:16:08 -0800363 if (data.IsPressed(kHang)) {
Austin Schuhd0629b12017-03-22 22:37:16 -0700364 new_superstructure_goal->intake.voltage_rollers = -10.0;
Austin Schuh3028b1d2017-03-11 22:12:13 -0800365 new_superstructure_goal->intake.disable_intake = true;
Austin Schuhd0629b12017-03-22 22:37:16 -0700366 } else if (data.IsPressed(kIntakeIn) || data.IsPressed(kFire)) {
367 if (robot_velocity_ > 2.0) {
368 new_superstructure_goal->intake.voltage_rollers = 12.0;
369 } else {
370 new_superstructure_goal->intake.voltage_rollers = 10.0;
371 }
Campbell Crowley71b5f132017-02-18 13:16:08 -0800372 } else if (data.IsPressed(kIntakeOut)) {
373 new_superstructure_goal->intake.voltage_rollers = -8.0;
Austin Schuh3028b1d2017-03-11 22:12:13 -0800374 }
375 if (intake_goal_ < 0.1) {
376 new_superstructure_goal->intake.voltage_rollers =
377 ::std::min(8.0, new_superstructure_goal->intake.voltage_rollers);
Campbell Crowley71b5f132017-02-18 13:16:08 -0800378 }
379
380 if (data.IsPressed(kReverseIndexer)) {
Austin Schuhd0629b12017-03-22 22:37:16 -0700381 new_superstructure_goal->indexer.voltage_rollers = -12.0;
Austin Schuh3028b1d2017-03-11 22:12:13 -0800382 new_superstructure_goal->indexer.angular_velocity = 4.0;
Campbell Crowley71b5f132017-02-18 13:16:08 -0800383 new_superstructure_goal->indexer.angular_velocity = 1.0;
Austin Schuh3028b1d2017-03-11 22:12:13 -0800384 } else if (fire_) {
Austin Schuhd0629b12017-03-22 22:37:16 -0700385 new_superstructure_goal->indexer.voltage_rollers = 12.0;
386 switch (last_shot_distance_) {
387 case ShotDistance::CLOSE_SHOT:
388 new_superstructure_goal->indexer.angular_velocity = -0.90 * M_PI;
389 break;
390 case ShotDistance::MIDDLE_SHOT:
391 case ShotDistance::FAR_SHOT:
392 new_superstructure_goal->indexer.angular_velocity = -2.25 * M_PI;
393 break;
394 }
Campbell Crowley71b5f132017-02-18 13:16:08 -0800395 } else {
396 new_superstructure_goal->indexer.voltage_rollers = 0.0;
397 new_superstructure_goal->indexer.angular_velocity = 0.0;
398 }
399
400 LOG_STRUCT(DEBUG, "sending goal", *new_superstructure_goal);
401 if (!new_superstructure_goal.Send()) {
402 LOG(ERROR, "Sending superstructure goal failed.\n");
403 }
404 }
405
406 private:
Austin Schuh3028b1d2017-03-11 22:12:13 -0800407 void StartAuto() {
408 LOG(INFO, "Starting auto mode\n");
409
410 ::frc971::autonomous::AutonomousActionParams params;
411 ::frc971::autonomous::auto_mode.FetchLatest();
412 if (::frc971::autonomous::auto_mode.get() != nullptr) {
413 params.mode = ::frc971::autonomous::auto_mode->mode;
414 } else {
415 LOG(WARNING, "no auto mode values\n");
416 params.mode = 0;
417 }
418 action_queue_.EnqueueAction(
419 ::frc971::autonomous::MakeAutonomousAction(params));
420 }
Campbell Crowley71b5f132017-02-18 13:16:08 -0800421
422 void StopAuto() {
423 LOG(INFO, "Stopping auto mode\n");
424 action_queue_.CancelAllActions();
425 }
426
427 // Current goals to send to the robot.
428 double intake_goal_ = 0.0;
429 double turret_goal_ = 0.0;
430 double hood_goal_ = 0.3;
431 double shooter_velocity_ = 0.0;
432
433 // Goals to send to the drivetrain in closed loop mode.
Austin Schuh3028b1d2017-03-11 22:12:13 -0800434 double left_goal_ = 0.0;
435 double right_goal_ = 0.0;
Campbell Crowley71b5f132017-02-18 13:16:08 -0800436
437 bool was_running_ = false;
438 bool auto_running_ = false;
439
440 bool vision_valid_ = false;
441
442 bool fire_ = false;
Austin Schuhd0629b12017-03-22 22:37:16 -0700443 double robot_velocity_ = 0.0;
Campbell Crowley71b5f132017-02-18 13:16:08 -0800444
445 ::aos::common::actions::ActionQueue action_queue_;
446};
447
448} // namespace joysticks
449} // namespace input
450} // namespace y2017
451
452int main() {
453 ::aos::Init(-1);
454 ::y2017::input::joysticks::Reader reader;
455 reader.Run();
456 ::aos::Cleanup();
457}