blob: a0f232055166f71300d572041c59141455c1e1bf [file] [log] [blame]
Brian Silverman17f503e2015-08-02 18:17:18 -07001#include <stdio.h>
2#include <string.h>
3#include <unistd.h>
4#include <math.h>
5
6#include "aos/linux_code/init.h"
Brian Silvermanc2065732015-11-28 22:55:30 +00007#include "aos/input/joystick_input.h"
Brian Silverman17f503e2015-08-02 18:17:18 -07008#include "aos/common/input/driver_station_data.h"
9#include "aos/common/logging/logging.h"
10#include "aos/common/util/log_interval.h"
11#include "aos/common/time.h"
12#include "aos/common/actions/actions.h"
13
14#include "y2014/control_loops/drivetrain/drivetrain.q.h"
15#include "y2014/constants.h"
16#include "frc971/queues/gyro.q.h"
17#include "frc971/autonomous/auto.q.h"
18#include "y2014/control_loops/claw/claw.q.h"
19#include "y2014/control_loops/shooter/shooter.q.h"
20#include "y2014/actors/shoot_actor.h"
21
Brian Silvermanb601d892015-12-20 18:24:38 -050022using ::y2014::control_loops::drivetrain_queue;
Brian Silverman17f503e2015-08-02 18:17:18 -070023using ::frc971::sensors::gyro_reading;
24
25using ::aos::input::driver_station::ButtonLocation;
26using ::aos::input::driver_station::JoystickAxis;
27using ::aos::input::driver_station::ControlBit;
28
29#define OLD_DS 0
30
Brian Silvermanb601d892015-12-20 18:24:38 -050031namespace y2014 {
Brian Silverman17f503e2015-08-02 18:17:18 -070032namespace input {
33namespace joysticks {
34
35const ButtonLocation kDriveControlLoopEnable1(1, 7),
36 kDriveControlLoopEnable2(1, 11);
37const JoystickAxis kSteeringWheel(1, 1), kDriveThrottle(2, 2);
38const ButtonLocation kShiftHigh(2, 1), kShiftLow(2, 3);
39const ButtonLocation kQuickTurn(1, 5);
40
41const ButtonLocation kCatch(3, 10);
42
43#if OLD_DS
44const ButtonLocation kFire(3, 11);
45const ButtonLocation kUnload(1, 4);
46const ButtonLocation kReload(1, 2);
47
48const ButtonLocation kRollersOut(3, 12);
49const ButtonLocation kRollersIn(3, 7);
50
51const ButtonLocation kTuck(3, 9);
52const ButtonLocation kIntakePosition(3, 8);
53const ButtonLocation kIntakeOpenPosition(3, 10);
54const ButtonLocation kVerticalTuck(3, 1);
55const JoystickAxis kFlipRobot(3, 3);
56
57const ButtonLocation kLongShot(3, 5);
58const ButtonLocation kCloseShot(3, 2);
59const ButtonLocation kFenderShot(3, 3);
60const ButtonLocation kTrussShot(2, 11);
61const ButtonLocation kHumanPlayerShot(3, 2);
62#else
63const ButtonLocation kFire(3, 9);
64const ButtonLocation kUnload(1, 4);
65const ButtonLocation kReload(1, 2);
66
67const ButtonLocation kRollersOut(3, 8);
68const ButtonLocation kRollersIn(3, 3);
69
70const ButtonLocation kTuck(3, 4);
71const ButtonLocation kIntakePosition(3, 5);
72const ButtonLocation kIntakeOpenPosition(3, 11);
73const ButtonLocation kVerticalTuck(2, 6);
74const JoystickAxis kFlipRobot(3, 3);
75
76const ButtonLocation kLongShot(3, 7);
77const ButtonLocation kCloseShot(3, 6);
78const ButtonLocation kFenderShot(3, 2);
79const ButtonLocation kTrussShot(2, 11);
80const ButtonLocation kHumanPlayerShot(3, 1);
81#endif
82
83const ButtonLocation kUserLeft(2, 7);
84const ButtonLocation kUserRight(2, 10);
85
86const JoystickAxis kAdjustClawGoal(3, 2);
87const JoystickAxis kAdjustClawSeparation(3, 1);
88
89struct ClawGoal {
90 double angle;
91 double separation;
92};
93
94struct ShotGoal {
95 ClawGoal claw;
96 double shot_power;
97 double velocity_compensation;
98 double intake_power;
99};
100
101const double kIntakePower = 4.0;
102// In case we have to quickly adjust it.
103const double kGrabSeparation = 0;
104const double kShootSeparation = 0.11 + kGrabSeparation;
105
106const ClawGoal kTuckGoal = {-2.273474, -0.749484};
107const ClawGoal kVerticalTuckGoal = {0, kGrabSeparation};
108const ClawGoal kIntakeGoal = {-2.24, kGrabSeparation};
109const ClawGoal kIntakeOpenGoal = {-2.0, 1.1};
110
111// TODO(austin): Tune these by hand...
112const ClawGoal kFlippedTuckGoal = {2.733474, -0.75};
113const ClawGoal kFlippedIntakeGoal = {2.0, kGrabSeparation};
114const ClawGoal kFlippedIntakeOpenGoal = {0.95, 1.0};
115
116// 34" between near edge of colored line and rear edge of bumper.
117// Only works running?
118const ShotGoal kLongShotGoal = {
119 {-1.08, kShootSeparation}, 145, 0.04, kIntakePower};
120// old 34" {-1.06, kShootSeparation}, 140, 0.04, kIntakePower};
121const ShotGoal kFlippedLongShotGoal = {
122 {0.96, kShootSeparation}, 145, 0.09, kIntakePower};
123// old 34" {0.96, kShootSeparation}, 140, 0.09, kIntakePower};
124
125// 78" between near edge of colored line and rear edge of bumper.
126const ShotGoal kCloseShotGoal = {
127 {-0.95, kShootSeparation}, 105, 0.2, kIntakePower};
128// 3/4" plunger {-0.90, kShootSeparation}, 105, 0.2, kIntakePower};
129const ShotGoal kFlippedMediumShotGoal = {
130 {0.865, kShootSeparation}, 120, 0.2, kIntakePower};
131// 3/4" plunger {0.80, kShootSeparation}, 105, 0.2, kIntakePower};
132
133// Shot from the fender.
134const ShotGoal kFenderShotGoal = {
135 {-0.68, kShootSeparation}, 115.0, 0.0, kIntakePower};
136const ShotGoal kFlippedShortShotGoal = {
137 {0.63, kShootSeparation}, 115.0, 0.0, kIntakePower};
138
139const ShotGoal kHumanShotGoal = {
140 {-0.90, kShootSeparation}, 140, 0.04, kIntakePower};
141const ShotGoal kFlippedHumanShotGoal = {
142 {0.90, kShootSeparation}, 140, 0, kIntakePower};
143const ShotGoal kTrussShotGoal = {
144 {-0.68, kShootSeparation}, 88.0, 0.4, kIntakePower};
145const ShotGoal kFlippedTrussShotGoal = {
146 {0.68, kShootSeparation}, 92.0, 0.4, kIntakePower};
147
148const ShotGoal kFlippedDemoShotGoal = {
149 {1.0, kShootSeparation}, 65.0, 0.0, kIntakePower};
150const ShotGoal kDemoShotGoal = {
151 {-1.0, kShootSeparation}, 50.0, 0.0, kIntakePower};
152
153const ClawGoal k254PassGoal = {-1.95, kGrabSeparation};
154const ClawGoal kFlipped254PassGoal = {1.96, kGrabSeparation};
155
156class Reader : public ::aos::input::JoystickInput {
157 public:
158 Reader()
159 : is_high_gear_(false),
160 shot_power_(80.0),
161 goal_angle_(0.0),
162 separation_angle_(kGrabSeparation),
163 velocity_compensation_(0.0),
164 intake_power_(0.0),
165 was_running_(false) {}
166
167 void RunIteration(const ::aos::input::driver_station::Data &data) override {
168 bool last_auto_running = auto_running_;
169 auto_running_ = data.GetControlBit(ControlBit::kAutonomous) &&
170 data.GetControlBit(ControlBit::kEnabled);
171 if (auto_running_ != last_auto_running) {
172 if (auto_running_) {
173 StartAuto();
174 } else {
175 StopAuto();
176 }
177 }
178
179 if (!data.GetControlBit(ControlBit::kAutonomous)) {
180 HandleDrivetrain(data);
181 HandleTeleop(data);
182 }
183 }
184
185 void HandleDrivetrain(const ::aos::input::driver_station::Data &data) {
186 bool is_control_loop_driving = false;
187 double left_goal = 0.0;
188 double right_goal = 0.0;
189 const double wheel = -data.GetAxis(kSteeringWheel);
190 const double throttle = -data.GetAxis(kDriveThrottle);
191 const double kThrottleGain = 1.0 / 2.5;
192 if (false && (data.IsPressed(kDriveControlLoopEnable1) ||
193 data.IsPressed(kDriveControlLoopEnable2))) {
194 // TODO(austin): Static sucks!
195 static double distance = 0.0;
196 static double angle = 0.0;
197 static double filtered_goal_distance = 0.0;
198 if (data.PosEdge(kDriveControlLoopEnable1) ||
199 data.PosEdge(kDriveControlLoopEnable2)) {
200 if (drivetrain_queue.position.FetchLatest() &&
201 gyro_reading.FetchLatest()) {
202 distance = (drivetrain_queue.position->left_encoder +
203 drivetrain_queue.position->right_encoder) /
204 2.0 -
205 throttle * kThrottleGain / 2.0;
206 angle = gyro_reading->angle;
207 filtered_goal_distance = distance;
208 }
209 }
210 is_control_loop_driving = true;
211
212 // const double gyro_angle = Gyro.View().angle;
213 const double goal_theta = angle - wheel * 0.27;
214 const double goal_distance = distance + throttle * kThrottleGain;
215 const double robot_width = 22.0 / 100.0 * 2.54;
216 const double kMaxVelocity = 0.6;
217 if (goal_distance > kMaxVelocity * 0.02 + filtered_goal_distance) {
218 filtered_goal_distance += kMaxVelocity * 0.02;
219 } else if (goal_distance <
220 -kMaxVelocity * 0.02 + filtered_goal_distance) {
221 filtered_goal_distance -= kMaxVelocity * 0.02;
222 } else {
223 filtered_goal_distance = goal_distance;
224 }
225 left_goal = filtered_goal_distance - robot_width * goal_theta / 2.0;
226 right_goal = filtered_goal_distance + robot_width * goal_theta / 2.0;
227 is_high_gear_ = false;
228
229 LOG(DEBUG, "Left goal %f Right goal %f\n", left_goal, right_goal);
230 }
231 if (!drivetrain_queue.goal.MakeWithBuilder()
232 .steering(wheel)
233 .throttle(throttle)
234 .highgear(is_high_gear_)
235 .quickturn(data.IsPressed(kQuickTurn))
236 .control_loop_driving(is_control_loop_driving)
237 .left_goal(left_goal)
238 .right_goal(right_goal)
239 .left_velocity_goal(0)
240 .right_velocity_goal(0)
241 .Send()) {
242 LOG(WARNING, "sending stick values failed\n");
243 }
244 if (data.PosEdge(kShiftHigh)) {
245 is_high_gear_ = false;
246 }
247 if (data.PosEdge(kShiftLow)) {
248 is_high_gear_ = true;
249 }
250 }
251
252 void SetGoal(ClawGoal goal) {
253 goal_angle_ = goal.angle;
254 separation_angle_ = goal.separation;
255 moving_for_shot_ = false;
256 velocity_compensation_ = 0.0;
257 intake_power_ = 0.0;
258 }
259
260 void SetGoal(ShotGoal goal) {
261 goal_angle_ = goal.claw.angle;
262 shot_separation_angle_ = goal.claw.separation;
263 separation_angle_ = kGrabSeparation;
264 moving_for_shot_ = true;
265 shot_power_ = goal.shot_power;
266 velocity_compensation_ = goal.velocity_compensation;
267 intake_power_ = goal.intake_power;
268 }
269
270 void HandleTeleop(const ::aos::input::driver_station::Data &data) {
271 if (!data.GetControlBit(ControlBit::kEnabled)) {
272 action_queue_.CancelAllActions();
273 LOG(DEBUG, "Canceling\n");
274 }
275 if (data.IsPressed(kRollersIn) || data.IsPressed(kRollersOut)) {
276 intake_power_ = 0.0;
277 separation_angle_ = kGrabSeparation;
278 moving_for_shot_ = false;
279 }
280
281 static const double kAdjustClawGoalDeadband = 0.08;
282 double claw_goal_adjust = data.GetAxis(kAdjustClawGoal);
283 if (OLD_DS || ::std::abs(claw_goal_adjust) < kAdjustClawGoalDeadband) {
284 claw_goal_adjust = 0;
285 } else {
286 claw_goal_adjust = (claw_goal_adjust -
287 ((claw_goal_adjust < 0) ? -kAdjustClawGoalDeadband
288 : kAdjustClawGoalDeadband)) *
289 0.035;
290 }
291 double claw_separation_adjust = data.GetAxis(kAdjustClawSeparation);
292 if (OLD_DS ||
293 ::std::abs(claw_separation_adjust) < kAdjustClawGoalDeadband) {
294 claw_separation_adjust = 0;
295 } else {
296 claw_separation_adjust =
297 (claw_separation_adjust -
298 ((claw_separation_adjust < 0) ? -kAdjustClawGoalDeadband
299 : kAdjustClawGoalDeadband)) *
300 -0.035;
301 }
302
303#if OLD_DS
304 if (data.IsPressed(kFenderShot)) {
305#else
306 if (data.GetAxis(kFlipRobot) > 0.9) {
307#endif
308 claw_goal_adjust += claw_separation_adjust;
309 claw_goal_adjust *= -1;
310
311 if (data.IsPressed(kIntakeOpenPosition)) {
312 action_queue_.CancelAllActions();
313 LOG(DEBUG, "Canceling\n");
314 SetGoal(kFlippedIntakeOpenGoal);
315 } else if (data.IsPressed(kIntakePosition)) {
316 action_queue_.CancelAllActions();
317 LOG(DEBUG, "Canceling\n");
318 SetGoal(kFlippedIntakeGoal);
319 } else if (data.IsPressed(kVerticalTuck)) {
320 action_queue_.CancelAllActions();
321 LOG(DEBUG, "Canceling\n");
322 SetGoal(kVerticalTuckGoal);
323 } else if (data.IsPressed(kTuck)) {
324 action_queue_.CancelAllActions();
325 LOG(DEBUG, "Canceling\n");
326 SetGoal(kFlippedTuckGoal);
327 } else if (data.PosEdge(kLongShot)) {
328 action_queue_.CancelAllActions();
329 LOG(DEBUG, "Canceling\n");
330 SetGoal(kFlippedLongShotGoal);
331 } else if (data.PosEdge(kCloseShot)) {
332 action_queue_.CancelAllActions();
333 LOG(DEBUG, "Canceling\n");
334 SetGoal(kFlippedMediumShotGoal);
335 } else if (data.PosEdge(kFenderShot)) {
336 action_queue_.CancelAllActions();
337 LOG(DEBUG, "Canceling\n");
338 SetGoal(kFlippedShortShotGoal);
339 } else if (data.PosEdge(kHumanPlayerShot)) {
340 action_queue_.CancelAllActions();
341 LOG(DEBUG, "Canceling\n");
342 SetGoal(kFlippedHumanShotGoal);
343 } else if (data.PosEdge(kUserLeft)) {
344 action_queue_.CancelAllActions();
345 LOG(DEBUG, "Canceling\n");
346 SetGoal(kFlipped254PassGoal);
347 } else if (data.PosEdge(kUserRight)) {
348 action_queue_.CancelAllActions();
349 LOG(DEBUG, "Canceling\n");
350 SetGoal(kFlippedDemoShotGoal);
351 } else if (data.PosEdge(kTrussShot)) {
352 action_queue_.CancelAllActions();
353 LOG(DEBUG, "Canceling\n");
354 SetGoal(kFlippedTrussShotGoal);
355 }
356 } else {
357 if (data.IsPressed(kIntakeOpenPosition)) {
358 action_queue_.CancelAllActions();
359 LOG(DEBUG, "Canceling\n");
360 SetGoal(kIntakeOpenGoal);
361 } else if (data.IsPressed(kIntakePosition)) {
362 action_queue_.CancelAllActions();
363 LOG(DEBUG, "Canceling\n");
364 SetGoal(kIntakeGoal);
365 } else if (data.IsPressed(kVerticalTuck)) {
366 action_queue_.CancelAllActions();
367 LOG(DEBUG, "Canceling\n");
368 SetGoal(kVerticalTuckGoal);
369 } else if (data.IsPressed(kTuck)) {
370 action_queue_.CancelAllActions();
371 LOG(DEBUG, "Canceling\n");
372 SetGoal(kTuckGoal);
373 } else if (data.PosEdge(kLongShot)) {
374 action_queue_.CancelAllActions();
375 LOG(DEBUG, "Canceling\n");
376 SetGoal(kLongShotGoal);
377 } else if (data.PosEdge(kCloseShot)) {
378 action_queue_.CancelAllActions();
379 LOG(DEBUG, "Canceling\n");
380 SetGoal(kCloseShotGoal);
381 } else if (data.PosEdge(kFenderShot)) {
382 action_queue_.CancelAllActions();
383 LOG(DEBUG, "Canceling\n");
384 SetGoal(kFenderShotGoal);
385 } else if (data.PosEdge(kHumanPlayerShot)) {
386 action_queue_.CancelAllActions();
387 LOG(DEBUG, "Canceling\n");
388 SetGoal(kHumanShotGoal);
389 } else if (data.PosEdge(kUserLeft)) {
390 action_queue_.CancelAllActions();
391 LOG(DEBUG, "Canceling\n");
392 SetGoal(k254PassGoal);
393 } else if (data.PosEdge(kUserRight)) {
394 action_queue_.CancelAllActions();
395 LOG(DEBUG, "Canceling\n");
396 SetGoal(kDemoShotGoal);
397 } else if (data.PosEdge(kTrussShot)) {
398 action_queue_.CancelAllActions();
399 LOG(DEBUG, "Canceling\n");
400 SetGoal(kTrussShotGoal);
401 }
402 }
403
404 if (data.PosEdge(kFire)) {
405 action_queue_.EnqueueAction(actors::MakeShootAction());
406 } else if (data.NegEdge(kFire)) {
407 action_queue_.CancelCurrentAction();
408 }
409
410 action_queue_.Tick();
411 if (data.IsPressed(kUnload) || data.IsPressed(kReload)) {
412 action_queue_.CancelAllActions();
413 LOG(DEBUG, "Canceling\n");
414 intake_power_ = 0.0;
415 velocity_compensation_ = 0.0;
416 }
417
418 // Send out the claw and shooter goals if no actions are running.
419 if (!action_queue_.Running()) {
420 goal_angle_ += claw_goal_adjust;
421 separation_angle_ += claw_separation_adjust;
422
423 // If the action just ended, turn the intake off and stop velocity
424 // compensating.
425 if (was_running_) {
426 intake_power_ = 0.0;
427 velocity_compensation_ = 0.0;
428 }
429
430 control_loops::drivetrain_queue.status.FetchLatest();
431 double goal_angle = goal_angle_;
432 if (control_loops::drivetrain_queue.status.get()) {
433 goal_angle += SpeedToAngleOffset(
434 control_loops::drivetrain_queue.status->robot_speed);
435 } else {
436 LOG_INTERVAL(no_drivetrain_status_);
437 }
438
439 if (moving_for_shot_) {
440 auto &claw_status = control_loops::claw_queue.status;
441 claw_status.FetchLatest();
442 if (claw_status.get()) {
443 if (::std::abs(claw_status->bottom - goal_angle) < 0.2) {
444 moving_for_shot_ = false;
445 separation_angle_ = shot_separation_angle_;
446 }
447 }
448 }
449
450 double separation_angle = separation_angle_;
451
452 if (data.IsPressed(kCatch)) {
453 const double kCatchSeparation = 1.0;
454 goal_angle -= kCatchSeparation / 2.0;
455 separation_angle = kCatchSeparation;
456 }
457
458 bool intaking =
459 data.IsPressed(kRollersIn) || data.IsPressed(kIntakePosition) ||
460 data.IsPressed(kIntakeOpenPosition) || data.IsPressed(kCatch);
461 if (!control_loops::claw_queue.goal.MakeWithBuilder()
462 .bottom_angle(goal_angle)
463 .separation_angle(separation_angle)
464 .intake(intaking ? 12.0
465 : (data.IsPressed(kRollersOut) ? -12.0
466 : intake_power_))
467 .centering(intaking ? 12.0 : 0.0)
468 .Send()) {
469 LOG(WARNING, "sending claw goal failed\n");
470 }
471
472 if (!control_loops::shooter_queue.goal.MakeWithBuilder()
473 .shot_power(shot_power_)
474 .shot_requested(data.IsPressed(kFire))
475 .unload_requested(data.IsPressed(kUnload))
476 .load_requested(data.IsPressed(kReload))
477 .Send()) {
478 LOG(WARNING, "sending shooter goal failed\n");
479 }
480 }
481 was_running_ = action_queue_.Running();
482 }
483
484 double SpeedToAngleOffset(double speed) {
Brian Silvermanb601d892015-12-20 18:24:38 -0500485 const ::y2014::constants::Values &values = ::y2014::constants::GetValues();
Brian Silverman17f503e2015-08-02 18:17:18 -0700486 // scale speed to a [0.0-1.0] on something close to the max
487 // TODO(austin): Change the scale factor for different shots.
488 return (speed / values.drivetrain_max_speed) * velocity_compensation_;
489 }
490
491 private:
492 void StartAuto() {
493 LOG(INFO, "Starting auto mode\n");
494 ::frc971::autonomous::autonomous.MakeWithBuilder().run_auto(true).Send();
495 }
496
497 void StopAuto() {
498 LOG(INFO, "Stopping auto mode\n");
499 ::frc971::autonomous::autonomous.MakeWithBuilder().run_auto(false).Send();
500 }
501
502 bool is_high_gear_;
503 double shot_power_;
504 double goal_angle_;
505 double separation_angle_, shot_separation_angle_;
506 double velocity_compensation_;
507 double intake_power_;
508 bool was_running_;
509 bool moving_for_shot_ = false;
510
511 bool auto_running_ = false;
Brian Silvermanb601d892015-12-20 18:24:38 -0500512
Brian Silverman17f503e2015-08-02 18:17:18 -0700513 ::aos::common::actions::ActionQueue action_queue_;
514
515 ::aos::util::SimpleLogInterval no_drivetrain_status_ =
516 ::aos::util::SimpleLogInterval(::aos::time::Time::InSeconds(0.2), WARNING,
517 "no drivetrain status");
518};
519
520} // namespace joysticks
521} // namespace input
Brian Silvermanb601d892015-12-20 18:24:38 -0500522} // namespace y2014
Brian Silverman17f503e2015-08-02 18:17:18 -0700523
524int main() {
525 ::aos::Init();
Brian Silvermanb601d892015-12-20 18:24:38 -0500526 ::y2014::input::joysticks::Reader reader;
Brian Silverman17f503e2015-08-02 18:17:18 -0700527 reader.Run();
528 ::aos::Cleanup();
529}