blob: 78a90e52dd92c8946e639f6f80f4e2f6da841790 [file] [log] [blame]
Brian Silverman756f9ff2014-01-17 23:40:23 -08001#include <stdio.h>
2#include <string.h>
3#include <unistd.h>
4#include <math.h>
5
6#include "aos/linux_code/init.h"
7#include "aos/prime/input/joystick_input.h"
Austin Schuh06cbbf12014-02-22 02:07:31 -08008#include "aos/common/input/driver_station_data.h"
Brian Silverman756f9ff2014-01-17 23:40:23 -08009#include "aos/common/logging/logging.h"
10
11#include "frc971/control_loops/drivetrain/drivetrain.q.h"
Austin Schuh5d8c5e72014-03-07 20:24:34 -080012#include "frc971/constants.h"
Ben Fredrickson81ba2d52014-03-02 08:21:46 +000013#include "frc971/queues/othersensors.q.h"
Brian Silverman756f9ff2014-01-17 23:40:23 -080014#include "frc971/autonomous/auto.q.h"
Brian Silvermanfac5c292014-02-17 15:26:57 -080015#include "frc971/control_loops/claw/claw.q.h"
16#include "frc971/control_loops/shooter/shooter.q.h"
Ben Fredricksonaa450452014-03-01 09:41:18 +000017#include "frc971/actions/shoot_action.q.h"
Brian Silverman756f9ff2014-01-17 23:40:23 -080018
19using ::frc971::control_loops::drivetrain;
Ben Fredrickson81ba2d52014-03-02 08:21:46 +000020using ::frc971::sensors::othersensors;
Brian Silverman756f9ff2014-01-17 23:40:23 -080021
22using ::aos::input::driver_station::ButtonLocation;
23using ::aos::input::driver_station::JoystickAxis;
24using ::aos::input::driver_station::ControlBit;
25
26namespace frc971 {
27namespace input {
28namespace joysticks {
29
30const ButtonLocation kDriveControlLoopEnable1(1, 7),
31 kDriveControlLoopEnable2(1, 11);
32const JoystickAxis kSteeringWheel(1, 1), kDriveThrottle(2, 2);
33const ButtonLocation kShiftHigh(2, 1), kShiftLow(2, 3);
34const ButtonLocation kQuickTurn(1, 5);
Austin Schuh58d23682014-02-23 01:39:50 -080035
Austin Schuh06cbbf12014-02-22 02:07:31 -080036const ButtonLocation kFire(3, 11);
Austin Schuh9cb836e2014-02-23 19:25:55 -080037const ButtonLocation kUnload(2, 11);
38const ButtonLocation kReload(2, 6);
Austin Schuh58d23682014-02-23 01:39:50 -080039
40const ButtonLocation kRollersOut(3, 12);
41const ButtonLocation kRollersIn(3, 10);
42
43const ButtonLocation kTuck(3, 8);
Austin Schuh9cb836e2014-02-23 19:25:55 -080044const ButtonLocation kIntakeOpenPosition(3, 9);
Austin Schuh58d23682014-02-23 01:39:50 -080045const ButtonLocation kIntakePosition(3, 7);
46
47const ButtonLocation kLongShot(3, 5);
48const ButtonLocation kMediumShot(3, 3);
49const ButtonLocation kShortShot(3, 6);
50
51struct ClawGoal {
52 double angle;
53 double separation;
54};
55
Austin Schuh5d8c5e72014-03-07 20:24:34 -080056struct ShotGoal {
57 ClawGoal claw;
58 double shot_power;
59 bool velocity_compensation;
60 double intake_power;
61};
62
Austin Schuh58d23682014-02-23 01:39:50 -080063const ClawGoal kTuckGoal = {-2.273474, -0.749484};
64const ClawGoal kIntakeGoal = {-2.273474, 0.0};
Austin Schuh9cb836e2014-02-23 19:25:55 -080065const ClawGoal kIntakeOpenGoal = {-2.0, 1.2};
Austin Schuh58d23682014-02-23 01:39:50 -080066
Austin Schuh5d8c5e72014-03-07 20:24:34 -080067const double kIntakePower = 2.0;
68
69const ShotGoal kLongShotGoal = {
70 {-M_PI / 2.0 + 0.43, 0.10}, 145, false, kIntakePower};
71const ShotGoal kMediumShotGoal = {{-0.9, 0.10}, 100, true, kIntakePower};
72const ShotGoal kShortShotGoal = {{-0.04, 0.10}, 40, false, kIntakePower};
Brian Silverman756f9ff2014-01-17 23:40:23 -080073
Austin Schuhb7dfabc2014-03-01 18:57:42 -080074class Action {
75 public:
76 // Cancels the action.
77 void Cancel() { DoCancel(); }
78 // Returns true if the action is currently running.
79 bool Running() { return DoRunning(); }
80 // Starts the action.
81 void Start() { DoStart(); }
82
Austin Schuhf8704992014-03-02 14:02:53 -080083 virtual ~Action() {}
84
Austin Schuhb7dfabc2014-03-01 18:57:42 -080085 private:
86 virtual void DoCancel() = 0;
87 virtual bool DoRunning() = 0;
88 virtual void DoStart() = 0;
89};
90
91// Templated subclass to hold the type information.
92template <typename T>
93class TypedAction : public Action {
94 public:
95 typedef typename std::remove_reference<
96 decltype(*(static_cast<T *>(NULL)->goal.MakeMessage().get()))>::type
97 GoalType;
98
99 TypedAction(T *queue_group)
100 : queue_group_(queue_group),
101 goal_(queue_group_->goal.MakeMessage()),
Austin Schuhc95c2b72014-03-02 11:56:49 -0800102 has_started_(false) {}
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800103
104 // Returns the current goal that will be sent when the action is sent.
105 GoalType *GetGoal() { return goal_.get(); }
106
Austin Schuhf8704992014-03-02 14:02:53 -0800107 virtual ~TypedAction() {
Austin Schuhc95c2b72014-03-02 11:56:49 -0800108 LOG(INFO, "Calling destructor\n");
109 DoCancel();
110 }
111
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800112 private:
113 // Cancels the action.
Austin Schuhc95c2b72014-03-02 11:56:49 -0800114 virtual void DoCancel() {
115 LOG(INFO, "Canceling action\n");
116 queue_group_->goal.MakeWithBuilder().run(false).Send();
117 }
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800118
119 // Returns true if the action is running or we don't have an initial response
120 // back from it to signal whether or not it is running.
121 virtual bool DoRunning() {
Austin Schuhc95c2b72014-03-02 11:56:49 -0800122 if (has_started_) {
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800123 queue_group_->status.FetchLatest();
124 } else if (queue_group_->status.FetchLatest()) {
Austin Schuhc95c2b72014-03-02 11:56:49 -0800125 if (queue_group_->status->running) {
126 // Wait until it reports that it is running to start.
127 has_started_ = true;
128 }
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800129 }
Austin Schuhc95c2b72014-03-02 11:56:49 -0800130 return !has_started_ ||
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800131 (queue_group_->status.get() && queue_group_->status->running);
132 }
133
134 // Starts the action if a goal has been created.
135 virtual void DoStart() {
136 if (goal_) {
137 goal_->run = true;
138 goal_.Send();
Austin Schuhc95c2b72014-03-02 11:56:49 -0800139 has_started_ = false;
140 LOG(INFO, "Starting action\n");
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800141 } else {
Austin Schuhc95c2b72014-03-02 11:56:49 -0800142 has_started_ = true;
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800143 }
144 }
145
146 T *queue_group_;
147 ::aos::ScopedMessagePtr<GoalType> goal_;
148 // Track if we have seen a response to the start message.
149 // If we haven't, we are considered running regardless.
Austin Schuhc95c2b72014-03-02 11:56:49 -0800150 bool has_started_;
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800151};
152
153// Makes a new ShootAction action.
154::std::unique_ptr<TypedAction< ::frc971::actions::ShootActionQueueGroup>>
155MakeShootAction() {
156 return ::std::unique_ptr<
157 TypedAction< ::frc971::actions::ShootActionQueueGroup>>(
158 new TypedAction< ::frc971::actions::ShootActionQueueGroup>(
159 &::frc971::actions::shoot_action));
160}
161
162// A queue which queues Actions and cancels them.
163class ActionQueue {
164 public:
165 // Queues up an action for sending.
166 void QueueAction(::std::unique_ptr<Action> action) {
167 if (current_action_) {
Austin Schuhc95c2b72014-03-02 11:56:49 -0800168 LOG(INFO, "Queueing action, canceling prior\n");
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800169 current_action_->Cancel();
170 next_action_ = ::std::move(action);
171 } else {
Austin Schuhc95c2b72014-03-02 11:56:49 -0800172 LOG(INFO, "Queueing action\n");
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800173 current_action_ = ::std::move(action);
174 current_action_->Start();
175 }
176 }
177
178 // Cancels the current action, and runs the next one when the current one has
179 // finished.
180 void CancelCurrentAction() {
Austin Schuhc95c2b72014-03-02 11:56:49 -0800181 LOG(INFO, "Canceling current action\n");
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800182 if (current_action_) {
183 current_action_->Cancel();
184 }
185 }
186
187 // Cancels all running actions.
188 void CancelAllActions() {
Austin Schuhc95c2b72014-03-02 11:56:49 -0800189 LOG(INFO, "Canceling all actions\n");
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800190 if (current_action_) {
191 current_action_->Cancel();
192 }
193 next_action_.reset();
194 }
195
196 // Runs the next action when the current one is finished running.
197 void Tick() {
198 if (current_action_) {
199 if (!current_action_->Running()) {
Austin Schuhc95c2b72014-03-02 11:56:49 -0800200 LOG(INFO, "Action is done.\n");
201 current_action_ = ::std::move(next_action_);
202 if (current_action_) {
203 LOG(INFO, "Running next action\n");
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800204 current_action_->Start();
205 }
206 }
207 }
208 }
209
210 // Returns true if any action is running or could be running.
211 // For a one cycle faster response, call Tick before running this.
212 bool Running() { return (bool)current_action_; }
213
214 private:
215 ::std::unique_ptr<Action> current_action_;
216 ::std::unique_ptr<Action> next_action_;
217};
218
Austin Schuh5d8c5e72014-03-07 20:24:34 -0800219
Brian Silverman756f9ff2014-01-17 23:40:23 -0800220class Reader : public ::aos::input::JoystickInput {
221 public:
Austin Schuh58d23682014-02-23 01:39:50 -0800222 Reader()
223 : is_high_gear_(false),
Austin Schuh9cb836e2014-02-23 19:25:55 -0800224 shot_power_(80.0),
Austin Schuh58d23682014-02-23 01:39:50 -0800225 goal_angle_(0.0),
Austin Schuh5d8c5e72014-03-07 20:24:34 -0800226 separation_angle_(0.0),
227 velocity_compensation_(false),
228 intake_power_(0.0),
229 was_running_(false) {}
Brian Silverman756f9ff2014-01-17 23:40:23 -0800230
231 virtual void RunIteration(const ::aos::input::driver_station::Data &data) {
Brian Silverman756f9ff2014-01-17 23:40:23 -0800232 if (data.GetControlBit(ControlBit::kAutonomous)) {
233 if (data.PosEdge(ControlBit::kEnabled)){
234 LOG(INFO, "Starting auto mode\n");
235 ::frc971::autonomous::autonomous.MakeWithBuilder()
Austin Schuh5d8c5e72014-03-07 20:24:34 -0800236 .run_auto(true)
237 .Send();
Brian Silverman756f9ff2014-01-17 23:40:23 -0800238 } else if (data.NegEdge(ControlBit::kEnabled)) {
239 LOG(INFO, "Stopping auto mode\n");
240 ::frc971::autonomous::autonomous.MakeWithBuilder()
Austin Schuh5d8c5e72014-03-07 20:24:34 -0800241 .run_auto(false)
242 .Send();
Brian Silverman756f9ff2014-01-17 23:40:23 -0800243 }
Austin Schuh58d23682014-02-23 01:39:50 -0800244 } else {
245 HandleTeleop(data);
Brian Silverman756f9ff2014-01-17 23:40:23 -0800246 }
247 }
Austin Schuh58d23682014-02-23 01:39:50 -0800248
249 void HandleDrivetrain(const ::aos::input::driver_station::Data &data) {
250 bool is_control_loop_driving = false;
251 double left_goal = 0.0;
252 double right_goal = 0.0;
253 const double wheel = -data.GetAxis(kSteeringWheel);
254 const double throttle = -data.GetAxis(kDriveThrottle);
255 const double kThrottleGain = 1.0 / 2.5;
256 if (false && (data.IsPressed(kDriveControlLoopEnable1) ||
257 data.IsPressed(kDriveControlLoopEnable2))) {
258 // TODO(austin): Static sucks!
259 static double distance = 0.0;
260 static double angle = 0.0;
261 static double filtered_goal_distance = 0.0;
262 if (data.PosEdge(kDriveControlLoopEnable1) ||
263 data.PosEdge(kDriveControlLoopEnable2)) {
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000264 if (drivetrain.position.FetchLatest() && othersensors.FetchLatest()) {
Austin Schuh58d23682014-02-23 01:39:50 -0800265 distance = (drivetrain.position->left_encoder +
266 drivetrain.position->right_encoder) /
267 2.0 -
268 throttle * kThrottleGain / 2.0;
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000269 angle = othersensors->gyro_angle;
Austin Schuh58d23682014-02-23 01:39:50 -0800270 filtered_goal_distance = distance;
271 }
272 }
273 is_control_loop_driving = true;
274
275 // const double gyro_angle = Gyro.View().angle;
276 const double goal_theta = angle - wheel * 0.27;
277 const double goal_distance = distance + throttle * kThrottleGain;
278 const double robot_width = 22.0 / 100.0 * 2.54;
279 const double kMaxVelocity = 0.6;
280 if (goal_distance > kMaxVelocity * 0.02 + filtered_goal_distance) {
281 filtered_goal_distance += kMaxVelocity * 0.02;
282 } else if (goal_distance <
283 -kMaxVelocity * 0.02 + filtered_goal_distance) {
284 filtered_goal_distance -= kMaxVelocity * 0.02;
285 } else {
286 filtered_goal_distance = goal_distance;
287 }
288 left_goal = filtered_goal_distance - robot_width * goal_theta / 2.0;
289 right_goal = filtered_goal_distance + robot_width * goal_theta / 2.0;
290 is_high_gear_ = false;
291
292 LOG(DEBUG, "Left goal %f Right goal %f\n", left_goal, right_goal);
293 }
294 if (!drivetrain.goal.MakeWithBuilder()
295 .steering(wheel)
296 .throttle(throttle)
297 .highgear(is_high_gear_)
298 .quickturn(data.IsPressed(kQuickTurn))
299 .control_loop_driving(is_control_loop_driving)
300 .left_goal(left_goal)
301 .right_goal(right_goal)
302 .Send()) {
303 LOG(WARNING, "sending stick values failed\n");
304 }
305 if (data.PosEdge(kShiftHigh)) {
306 is_high_gear_ = false;
307 }
308 if (data.PosEdge(kShiftLow)) {
309 is_high_gear_ = true;
310 }
311 }
312
313 void SetGoal(ClawGoal goal) {
314 goal_angle_ = goal.angle;
315 separation_angle_ = goal.separation;
Austin Schuh5d8c5e72014-03-07 20:24:34 -0800316 velocity_compensation_ = false;
317 intake_power_ = 0.0;
318 }
319
320 void SetGoal(ShotGoal goal) {
321 goal_angle_ = goal.claw.angle;
322 separation_angle_ = goal.claw.separation;
323 shot_power_ = goal.shot_power;
324 velocity_compensation_ = goal.velocity_compensation;
325 intake_power_ = goal.intake_power;
Austin Schuh58d23682014-02-23 01:39:50 -0800326 }
327
328 void HandleTeleop(const ::aos::input::driver_station::Data &data) {
329 HandleDrivetrain(data);
Austin Schuhc95c2b72014-03-02 11:56:49 -0800330 if (!data.GetControlBit(ControlBit::kEnabled)) {
331 action_queue_.CancelAllActions();
332 }
Austin Schuh5d8c5e72014-03-07 20:24:34 -0800333 if (data.IsPressed(kRollersIn) || data.IsPressed(kRollersOut)) {
334 intake_power_ = 0.0;
335 }
Austin Schuh58d23682014-02-23 01:39:50 -0800336
Austin Schuh9cb836e2014-02-23 19:25:55 -0800337 if (data.IsPressed(kIntakeOpenPosition)) {
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800338 action_queue_.CancelAllActions();
Austin Schuh9cb836e2014-02-23 19:25:55 -0800339 SetGoal(kIntakeOpenGoal);
340 } else if (data.IsPressed(kIntakePosition)) {
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800341 action_queue_.CancelAllActions();
Austin Schuh58d23682014-02-23 01:39:50 -0800342 SetGoal(kIntakeGoal);
343 } else if (data.IsPressed(kTuck)) {
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800344 action_queue_.CancelAllActions();
Austin Schuh58d23682014-02-23 01:39:50 -0800345 SetGoal(kTuckGoal);
346 }
347
Ben Fredricksonaa450452014-03-01 09:41:18 +0000348 if (data.PosEdge(kLongShot)) {
Austin Schuh5d8c5e72014-03-07 20:24:34 -0800349 action_queue_.CancelAllActions();
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800350 SetGoal(kLongShotGoal);
Ben Fredricksonf465a062014-03-02 00:18:59 +0000351 } else if (data.PosEdge(kMediumShot)) {
Austin Schuh5d8c5e72014-03-07 20:24:34 -0800352 action_queue_.CancelAllActions();
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800353 SetGoal(kMediumShotGoal);
Ben Fredricksonf465a062014-03-02 00:18:59 +0000354 } else if (data.PosEdge(kShortShot)) {
Austin Schuh5d8c5e72014-03-07 20:24:34 -0800355 action_queue_.CancelAllActions();
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800356 SetGoal(kShortShotGoal);
Austin Schuh5d8c5e72014-03-07 20:24:34 -0800357 }
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800358
Austin Schuh5d8c5e72014-03-07 20:24:34 -0800359 if (data.PosEdge(kFire)) {
360 action_queue_.QueueAction(MakeShootAction());
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800361 }
362
363 action_queue_.Tick();
Austin Schuhc95c2b72014-03-02 11:56:49 -0800364 if (data.IsPressed(kUnload) || data.IsPressed(kReload)) {
365 action_queue_.CancelAllActions();
366 }
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800367
368 // Send out the claw and shooter goals if no actions are running.
369 if (!action_queue_.Running()) {
Austin Schuh5d8c5e72014-03-07 20:24:34 -0800370 // If the action just ended, turn the intake off and stop velocity compensating.
371 if (was_running_) {
372 intake_power_ = 0.0;
373 velocity_compensation_ = false;
374 }
375
376 control_loops::drivetrain.status.FetchLatest();
377 const double goal_angle =
378 goal_angle_ +
379 (velocity_compensation_
380 ? SpeedToAngleOffset(
381 control_loops::drivetrain.status->robot_speed)
382 : 0.0);
383
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800384 if (!control_loops::claw_queue_group.goal.MakeWithBuilder()
Austin Schuh5d8c5e72014-03-07 20:24:34 -0800385 .bottom_angle(goal_angle)
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800386 .separation_angle(separation_angle_)
387 .intake(data.IsPressed(kRollersIn)
388 ? 12.0
Austin Schuh5d8c5e72014-03-07 20:24:34 -0800389 : (data.IsPressed(kRollersOut) ? -12.0 : intake_power_))
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800390 .centering(data.IsPressed(kRollersIn) ? 12.0 : 0.0)
391 .Send()) {
392 LOG(WARNING, "sending claw goal failed\n");
393 }
394
395 if (!control_loops::shooter_queue_group.goal.MakeWithBuilder()
396 .shot_power(shot_power_)
397 .shot_requested(data.IsPressed(kFire))
398 .unload_requested(data.IsPressed(kUnload))
399 .load_requested(data.IsPressed(kReload))
400 .Send()) {
401 LOG(WARNING, "sending shooter goal failed\n");
402 }
Austin Schuh58d23682014-02-23 01:39:50 -0800403 }
Austin Schuh5d8c5e72014-03-07 20:24:34 -0800404 was_running_ = action_queue_.Running();
405 }
406
407 double SpeedToAngleOffset(double speed) {
408 const frc971::constants::Values &values = frc971::constants::GetValues();
409 // scale speed to a [0.0-1.0] on something close to the max
410 // TODO(austin): Change the scale factor for different shots.
411 return (speed / values.drivetrain_max_speed) * 0.3;
Austin Schuh58d23682014-02-23 01:39:50 -0800412 }
413
Austin Schuh01c652b2014-02-21 23:13:42 -0800414 private:
Austin Schuh58d23682014-02-23 01:39:50 -0800415 bool is_high_gear_;
416 double shot_power_;
417 double goal_angle_;
418 double separation_angle_;
Austin Schuh5d8c5e72014-03-07 20:24:34 -0800419 bool velocity_compensation_;
420 double intake_power_;
421 bool was_running_;
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800422
423 ActionQueue action_queue_;
Brian Silverman756f9ff2014-01-17 23:40:23 -0800424};
425
426} // namespace joysticks
427} // namespace input
428} // namespace frc971
429
430int main() {
431 ::aos::Init();
432 ::frc971::input::joysticks::Reader reader;
433 reader.Run();
434 ::aos::Cleanup();
435}