blob: ee1756fd260cf59a348b7bafff2db46625dc2c91 [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"
Ben Fredrickson81ba2d52014-03-02 08:21:46 +000012#include "frc971/queues/othersensors.q.h"
Brian Silverman756f9ff2014-01-17 23:40:23 -080013#include "frc971/autonomous/auto.q.h"
Brian Silvermanfac5c292014-02-17 15:26:57 -080014#include "frc971/control_loops/claw/claw.q.h"
15#include "frc971/control_loops/shooter/shooter.q.h"
Ben Fredricksonaa450452014-03-01 09:41:18 +000016#include "frc971/actions/shoot_action.q.h"
Brian Silverman756f9ff2014-01-17 23:40:23 -080017
18using ::frc971::control_loops::drivetrain;
Ben Fredrickson81ba2d52014-03-02 08:21:46 +000019using ::frc971::sensors::othersensors;
Brian Silverman756f9ff2014-01-17 23:40:23 -080020
21using ::aos::input::driver_station::ButtonLocation;
22using ::aos::input::driver_station::JoystickAxis;
23using ::aos::input::driver_station::ControlBit;
24
25namespace frc971 {
26namespace input {
27namespace joysticks {
28
29const ButtonLocation kDriveControlLoopEnable1(1, 7),
30 kDriveControlLoopEnable2(1, 11);
31const JoystickAxis kSteeringWheel(1, 1), kDriveThrottle(2, 2);
32const ButtonLocation kShiftHigh(2, 1), kShiftLow(2, 3);
33const ButtonLocation kQuickTurn(1, 5);
Austin Schuh58d23682014-02-23 01:39:50 -080034
Austin Schuh06cbbf12014-02-22 02:07:31 -080035const ButtonLocation kFire(3, 11);
Austin Schuh9cb836e2014-02-23 19:25:55 -080036const ButtonLocation kUnload(2, 11);
37const ButtonLocation kReload(2, 6);
Austin Schuh58d23682014-02-23 01:39:50 -080038
39const ButtonLocation kRollersOut(3, 12);
40const ButtonLocation kRollersIn(3, 10);
41
42const ButtonLocation kTuck(3, 8);
Austin Schuh9cb836e2014-02-23 19:25:55 -080043const ButtonLocation kIntakeOpenPosition(3, 9);
Austin Schuh58d23682014-02-23 01:39:50 -080044const ButtonLocation kIntakePosition(3, 7);
45
46const ButtonLocation kLongShot(3, 5);
47const ButtonLocation kMediumShot(3, 3);
48const ButtonLocation kShortShot(3, 6);
49
50struct ClawGoal {
51 double angle;
52 double separation;
53};
54
55const ClawGoal kTuckGoal = {-2.273474, -0.749484};
56const ClawGoal kIntakeGoal = {-2.273474, 0.0};
Austin Schuh9cb836e2014-02-23 19:25:55 -080057const ClawGoal kIntakeOpenGoal = {-2.0, 1.2};
Austin Schuh58d23682014-02-23 01:39:50 -080058
Austin Schuh9cb836e2014-02-23 19:25:55 -080059const ClawGoal kLongShotGoal = {-M_PI / 2.0 + 0.43, 0.10};
60const ClawGoal kMediumShotGoal = {-0.9, 0.10};
61const ClawGoal kShortShotGoal = {-0.04, 0.11};
Brian Silverman756f9ff2014-01-17 23:40:23 -080062
Austin Schuhb7dfabc2014-03-01 18:57:42 -080063class Action {
64 public:
65 // Cancels the action.
66 void Cancel() { DoCancel(); }
67 // Returns true if the action is currently running.
68 bool Running() { return DoRunning(); }
69 // Starts the action.
70 void Start() { DoStart(); }
71
Austin Schuhf8704992014-03-02 14:02:53 -080072 virtual ~Action() {}
73
Austin Schuhb7dfabc2014-03-01 18:57:42 -080074 private:
75 virtual void DoCancel() = 0;
76 virtual bool DoRunning() = 0;
77 virtual void DoStart() = 0;
78};
79
80// Templated subclass to hold the type information.
81template <typename T>
82class TypedAction : public Action {
83 public:
84 typedef typename std::remove_reference<
85 decltype(*(static_cast<T *>(NULL)->goal.MakeMessage().get()))>::type
86 GoalType;
87
88 TypedAction(T *queue_group)
89 : queue_group_(queue_group),
90 goal_(queue_group_->goal.MakeMessage()),
Austin Schuhc95c2b72014-03-02 11:56:49 -080091 has_started_(false) {}
Austin Schuhb7dfabc2014-03-01 18:57:42 -080092
93 // Returns the current goal that will be sent when the action is sent.
94 GoalType *GetGoal() { return goal_.get(); }
95
Austin Schuhf8704992014-03-02 14:02:53 -080096 virtual ~TypedAction() {
Austin Schuhc95c2b72014-03-02 11:56:49 -080097 LOG(INFO, "Calling destructor\n");
98 DoCancel();
99 }
100
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800101 private:
102 // Cancels the action.
Austin Schuhc95c2b72014-03-02 11:56:49 -0800103 virtual void DoCancel() {
104 LOG(INFO, "Canceling action\n");
105 queue_group_->goal.MakeWithBuilder().run(false).Send();
106 }
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800107
108 // Returns true if the action is running or we don't have an initial response
109 // back from it to signal whether or not it is running.
110 virtual bool DoRunning() {
Austin Schuhc95c2b72014-03-02 11:56:49 -0800111 if (has_started_) {
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800112 queue_group_->status.FetchLatest();
113 } else if (queue_group_->status.FetchLatest()) {
Austin Schuhc95c2b72014-03-02 11:56:49 -0800114 if (queue_group_->status->running) {
115 // Wait until it reports that it is running to start.
116 has_started_ = true;
117 }
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800118 }
Austin Schuhc95c2b72014-03-02 11:56:49 -0800119 return !has_started_ ||
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800120 (queue_group_->status.get() && queue_group_->status->running);
121 }
122
123 // Starts the action if a goal has been created.
124 virtual void DoStart() {
125 if (goal_) {
126 goal_->run = true;
127 goal_.Send();
Austin Schuhc95c2b72014-03-02 11:56:49 -0800128 has_started_ = false;
129 LOG(INFO, "Starting action\n");
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800130 } else {
Austin Schuhc95c2b72014-03-02 11:56:49 -0800131 has_started_ = true;
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800132 }
133 }
134
135 T *queue_group_;
136 ::aos::ScopedMessagePtr<GoalType> goal_;
137 // Track if we have seen a response to the start message.
138 // If we haven't, we are considered running regardless.
Austin Schuhc95c2b72014-03-02 11:56:49 -0800139 bool has_started_;
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800140};
141
142// Makes a new ShootAction action.
143::std::unique_ptr<TypedAction< ::frc971::actions::ShootActionQueueGroup>>
144MakeShootAction() {
145 return ::std::unique_ptr<
146 TypedAction< ::frc971::actions::ShootActionQueueGroup>>(
147 new TypedAction< ::frc971::actions::ShootActionQueueGroup>(
148 &::frc971::actions::shoot_action));
149}
150
151// A queue which queues Actions and cancels them.
152class ActionQueue {
153 public:
154 // Queues up an action for sending.
155 void QueueAction(::std::unique_ptr<Action> action) {
156 if (current_action_) {
Austin Schuhc95c2b72014-03-02 11:56:49 -0800157 LOG(INFO, "Queueing action, canceling prior\n");
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800158 current_action_->Cancel();
159 next_action_ = ::std::move(action);
160 } else {
Austin Schuhc95c2b72014-03-02 11:56:49 -0800161 LOG(INFO, "Queueing action\n");
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800162 current_action_ = ::std::move(action);
163 current_action_->Start();
164 }
165 }
166
167 // Cancels the current action, and runs the next one when the current one has
168 // finished.
169 void CancelCurrentAction() {
Austin Schuhc95c2b72014-03-02 11:56:49 -0800170 LOG(INFO, "Canceling current action\n");
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800171 if (current_action_) {
172 current_action_->Cancel();
173 }
174 }
175
176 // Cancels all running actions.
177 void CancelAllActions() {
Austin Schuhc95c2b72014-03-02 11:56:49 -0800178 LOG(INFO, "Canceling all actions\n");
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800179 if (current_action_) {
180 current_action_->Cancel();
181 }
182 next_action_.reset();
183 }
184
185 // Runs the next action when the current one is finished running.
186 void Tick() {
187 if (current_action_) {
188 if (!current_action_->Running()) {
Austin Schuhc95c2b72014-03-02 11:56:49 -0800189 LOG(INFO, "Action is done.\n");
190 current_action_ = ::std::move(next_action_);
191 if (current_action_) {
192 LOG(INFO, "Running next action\n");
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800193 current_action_->Start();
194 }
195 }
196 }
197 }
198
199 // Returns true if any action is running or could be running.
200 // For a one cycle faster response, call Tick before running this.
201 bool Running() { return (bool)current_action_; }
202
203 private:
204 ::std::unique_ptr<Action> current_action_;
205 ::std::unique_ptr<Action> next_action_;
206};
207
Brian Silverman756f9ff2014-01-17 23:40:23 -0800208class Reader : public ::aos::input::JoystickInput {
209 public:
Austin Schuh58d23682014-02-23 01:39:50 -0800210 Reader()
211 : is_high_gear_(false),
Austin Schuh9cb836e2014-02-23 19:25:55 -0800212 shot_power_(80.0),
Austin Schuh58d23682014-02-23 01:39:50 -0800213 goal_angle_(0.0),
214 separation_angle_(0.0) {}
Brian Silverman756f9ff2014-01-17 23:40:23 -0800215
216 virtual void RunIteration(const ::aos::input::driver_station::Data &data) {
Brian Silverman756f9ff2014-01-17 23:40:23 -0800217 if (data.GetControlBit(ControlBit::kAutonomous)) {
218 if (data.PosEdge(ControlBit::kEnabled)){
219 LOG(INFO, "Starting auto mode\n");
220 ::frc971::autonomous::autonomous.MakeWithBuilder()
221 .run_auto(true).Send();
222 } else if (data.NegEdge(ControlBit::kEnabled)) {
223 LOG(INFO, "Stopping auto mode\n");
224 ::frc971::autonomous::autonomous.MakeWithBuilder()
225 .run_auto(false).Send();
226 }
Austin Schuh58d23682014-02-23 01:39:50 -0800227 } else {
228 HandleTeleop(data);
Brian Silverman756f9ff2014-01-17 23:40:23 -0800229 }
230 }
Austin Schuh58d23682014-02-23 01:39:50 -0800231
232 void HandleDrivetrain(const ::aos::input::driver_station::Data &data) {
233 bool is_control_loop_driving = false;
234 double left_goal = 0.0;
235 double right_goal = 0.0;
236 const double wheel = -data.GetAxis(kSteeringWheel);
237 const double throttle = -data.GetAxis(kDriveThrottle);
238 const double kThrottleGain = 1.0 / 2.5;
239 if (false && (data.IsPressed(kDriveControlLoopEnable1) ||
240 data.IsPressed(kDriveControlLoopEnable2))) {
241 // TODO(austin): Static sucks!
242 static double distance = 0.0;
243 static double angle = 0.0;
244 static double filtered_goal_distance = 0.0;
245 if (data.PosEdge(kDriveControlLoopEnable1) ||
246 data.PosEdge(kDriveControlLoopEnable2)) {
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000247 if (drivetrain.position.FetchLatest() && othersensors.FetchLatest()) {
Austin Schuh58d23682014-02-23 01:39:50 -0800248 distance = (drivetrain.position->left_encoder +
249 drivetrain.position->right_encoder) /
250 2.0 -
251 throttle * kThrottleGain / 2.0;
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000252 angle = othersensors->gyro_angle;
Austin Schuh58d23682014-02-23 01:39:50 -0800253 filtered_goal_distance = distance;
254 }
255 }
256 is_control_loop_driving = true;
257
258 // const double gyro_angle = Gyro.View().angle;
259 const double goal_theta = angle - wheel * 0.27;
260 const double goal_distance = distance + throttle * kThrottleGain;
261 const double robot_width = 22.0 / 100.0 * 2.54;
262 const double kMaxVelocity = 0.6;
263 if (goal_distance > kMaxVelocity * 0.02 + filtered_goal_distance) {
264 filtered_goal_distance += kMaxVelocity * 0.02;
265 } else if (goal_distance <
266 -kMaxVelocity * 0.02 + filtered_goal_distance) {
267 filtered_goal_distance -= kMaxVelocity * 0.02;
268 } else {
269 filtered_goal_distance = goal_distance;
270 }
271 left_goal = filtered_goal_distance - robot_width * goal_theta / 2.0;
272 right_goal = filtered_goal_distance + robot_width * goal_theta / 2.0;
273 is_high_gear_ = false;
274
275 LOG(DEBUG, "Left goal %f Right goal %f\n", left_goal, right_goal);
276 }
277 if (!drivetrain.goal.MakeWithBuilder()
278 .steering(wheel)
279 .throttle(throttle)
280 .highgear(is_high_gear_)
281 .quickturn(data.IsPressed(kQuickTurn))
282 .control_loop_driving(is_control_loop_driving)
283 .left_goal(left_goal)
284 .right_goal(right_goal)
285 .Send()) {
286 LOG(WARNING, "sending stick values failed\n");
287 }
288 if (data.PosEdge(kShiftHigh)) {
289 is_high_gear_ = false;
290 }
291 if (data.PosEdge(kShiftLow)) {
292 is_high_gear_ = true;
293 }
294 }
295
296 void SetGoal(ClawGoal goal) {
297 goal_angle_ = goal.angle;
298 separation_angle_ = goal.separation;
299 }
300
301 void HandleTeleop(const ::aos::input::driver_station::Data &data) {
302 HandleDrivetrain(data);
Austin Schuhc95c2b72014-03-02 11:56:49 -0800303 if (!data.GetControlBit(ControlBit::kEnabled)) {
304 action_queue_.CancelAllActions();
305 }
Austin Schuh58d23682014-02-23 01:39:50 -0800306
Austin Schuh9cb836e2014-02-23 19:25:55 -0800307 if (data.IsPressed(kIntakeOpenPosition)) {
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800308 action_queue_.CancelAllActions();
Austin Schuh9cb836e2014-02-23 19:25:55 -0800309 SetGoal(kIntakeOpenGoal);
310 } else if (data.IsPressed(kIntakePosition)) {
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800311 action_queue_.CancelAllActions();
Austin Schuh58d23682014-02-23 01:39:50 -0800312 SetGoal(kIntakeGoal);
313 } else if (data.IsPressed(kTuck)) {
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800314 action_queue_.CancelAllActions();
Austin Schuh58d23682014-02-23 01:39:50 -0800315 SetGoal(kTuckGoal);
316 }
317
Ben Fredricksonaa450452014-03-01 09:41:18 +0000318 if (data.PosEdge(kLongShot)) {
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800319 auto shoot_action = MakeShootAction();
320
321 shot_power_ = 160.0;
322 shoot_action->GetGoal()->shot_power = shot_power_;
323 shoot_action->GetGoal()->shot_angle = kLongShotGoal.angle;
324 SetGoal(kLongShotGoal);
325
326 action_queue_.QueueAction(::std::move(shoot_action));
Ben Fredricksonf465a062014-03-02 00:18:59 +0000327 } else if (data.PosEdge(kMediumShot)) {
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800328 auto shoot_action = MakeShootAction();
329
330 shot_power_ = 100.0;
331 shoot_action->GetGoal()->shot_power = shot_power_;
332 shoot_action->GetGoal()->shot_angle = kMediumShotGoal.angle;
333 SetGoal(kMediumShotGoal);
334
335 action_queue_.QueueAction(::std::move(shoot_action));
Ben Fredricksonf465a062014-03-02 00:18:59 +0000336 } else if (data.PosEdge(kShortShot)) {
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800337 auto shoot_action = MakeShootAction();
338
Austin Schuhc95c2b72014-03-02 11:56:49 -0800339 shot_power_ = 20.0;
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800340 shoot_action->GetGoal()->shot_power = shot_power_;
341 shoot_action->GetGoal()->shot_angle = kShortShotGoal.angle;
342 SetGoal(kShortShotGoal);
343
344 action_queue_.QueueAction(::std::move(shoot_action));
345 }
346
347 action_queue_.Tick();
Austin Schuhc95c2b72014-03-02 11:56:49 -0800348 if (data.IsPressed(kUnload) || data.IsPressed(kReload)) {
349 action_queue_.CancelAllActions();
350 }
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800351
352 // Send out the claw and shooter goals if no actions are running.
353 if (!action_queue_.Running()) {
354 if (!control_loops::claw_queue_group.goal.MakeWithBuilder()
355 .bottom_angle(goal_angle_)
356 .separation_angle(separation_angle_)
357 .intake(data.IsPressed(kRollersIn)
358 ? 12.0
359 : (data.IsPressed(kRollersOut) ? -12.0 : 0.0))
360 .centering(data.IsPressed(kRollersIn) ? 12.0 : 0.0)
361 .Send()) {
362 LOG(WARNING, "sending claw goal failed\n");
363 }
364
365 if (!control_loops::shooter_queue_group.goal.MakeWithBuilder()
366 .shot_power(shot_power_)
367 .shot_requested(data.IsPressed(kFire))
368 .unload_requested(data.IsPressed(kUnload))
369 .load_requested(data.IsPressed(kReload))
370 .Send()) {
371 LOG(WARNING, "sending shooter goal failed\n");
372 }
Austin Schuh58d23682014-02-23 01:39:50 -0800373 }
374 }
375
Austin Schuh01c652b2014-02-21 23:13:42 -0800376 private:
Austin Schuh58d23682014-02-23 01:39:50 -0800377 bool is_high_gear_;
378 double shot_power_;
379 double goal_angle_;
380 double separation_angle_;
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800381
382 ActionQueue action_queue_;
Brian Silverman756f9ff2014-01-17 23:40:23 -0800383};
384
385} // namespace joysticks
386} // namespace input
387} // namespace frc971
388
389int main() {
390 ::aos::Init();
391 ::frc971::input::joysticks::Reader reader;
392 reader.Run();
393 ::aos::Cleanup();
394}