blob: 9e57e6f42555e2beca75cbd1a9e6df92d9f0128f [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
72 private:
73 virtual void DoCancel() = 0;
74 virtual bool DoRunning() = 0;
75 virtual void DoStart() = 0;
76};
77
78// Templated subclass to hold the type information.
79template <typename T>
80class TypedAction : public Action {
81 public:
82 typedef typename std::remove_reference<
83 decltype(*(static_cast<T *>(NULL)->goal.MakeMessage().get()))>::type
84 GoalType;
85
86 TypedAction(T *queue_group)
87 : queue_group_(queue_group),
88 goal_(queue_group_->goal.MakeMessage()),
89 has_seen_response_(false) {}
90
91 // Returns the current goal that will be sent when the action is sent.
92 GoalType *GetGoal() { return goal_.get(); }
93
94 private:
95 // Cancels the action.
96 virtual void DoCancel() { queue_group_->goal.MakeWithBuilder().run(false).Send(); }
97
98 // Returns true if the action is running or we don't have an initial response
99 // back from it to signal whether or not it is running.
100 virtual bool DoRunning() {
101 if (has_seen_response_) {
102 queue_group_->status.FetchLatest();
103 } else if (queue_group_->status.FetchLatest()) {
104 has_seen_response_ = true;
105 }
106 return !has_seen_response_ ||
107 (queue_group_->status.get() && queue_group_->status->running);
108 }
109
110 // Starts the action if a goal has been created.
111 virtual void DoStart() {
112 if (goal_) {
113 goal_->run = true;
114 goal_.Send();
115 has_seen_response_ = false;
116 } else {
117 has_seen_response_ = true;
118 }
119 }
120
121 T *queue_group_;
122 ::aos::ScopedMessagePtr<GoalType> goal_;
123 // Track if we have seen a response to the start message.
124 // If we haven't, we are considered running regardless.
125 bool has_seen_response_;
126};
127
128// Makes a new ShootAction action.
129::std::unique_ptr<TypedAction< ::frc971::actions::ShootActionQueueGroup>>
130MakeShootAction() {
131 return ::std::unique_ptr<
132 TypedAction< ::frc971::actions::ShootActionQueueGroup>>(
133 new TypedAction< ::frc971::actions::ShootActionQueueGroup>(
134 &::frc971::actions::shoot_action));
135}
136
137// A queue which queues Actions and cancels them.
138class ActionQueue {
139 public:
140 // Queues up an action for sending.
141 void QueueAction(::std::unique_ptr<Action> action) {
142 if (current_action_) {
143 current_action_->Cancel();
144 next_action_ = ::std::move(action);
145 } else {
146 current_action_ = ::std::move(action);
147 current_action_->Start();
148 }
149 }
150
151 // Cancels the current action, and runs the next one when the current one has
152 // finished.
153 void CancelCurrentAction() {
154 if (current_action_) {
155 current_action_->Cancel();
156 }
157 }
158
159 // Cancels all running actions.
160 void CancelAllActions() {
161 if (current_action_) {
162 current_action_->Cancel();
163 }
164 next_action_.reset();
165 }
166
167 // Runs the next action when the current one is finished running.
168 void Tick() {
169 if (current_action_) {
170 if (!current_action_->Running()) {
171 if (next_action_) {
172 current_action_ = ::std::move(next_action_);
173 current_action_->Start();
174 }
175 }
176 }
177 }
178
179 // Returns true if any action is running or could be running.
180 // For a one cycle faster response, call Tick before running this.
181 bool Running() { return (bool)current_action_; }
182
183 private:
184 ::std::unique_ptr<Action> current_action_;
185 ::std::unique_ptr<Action> next_action_;
186};
187
Brian Silverman756f9ff2014-01-17 23:40:23 -0800188class Reader : public ::aos::input::JoystickInput {
189 public:
Austin Schuh58d23682014-02-23 01:39:50 -0800190 Reader()
191 : is_high_gear_(false),
Austin Schuh9cb836e2014-02-23 19:25:55 -0800192 shot_power_(80.0),
Austin Schuh58d23682014-02-23 01:39:50 -0800193 goal_angle_(0.0),
194 separation_angle_(0.0) {}
Brian Silverman756f9ff2014-01-17 23:40:23 -0800195
196 virtual void RunIteration(const ::aos::input::driver_station::Data &data) {
Brian Silverman756f9ff2014-01-17 23:40:23 -0800197 if (data.GetControlBit(ControlBit::kAutonomous)) {
198 if (data.PosEdge(ControlBit::kEnabled)){
199 LOG(INFO, "Starting auto mode\n");
200 ::frc971::autonomous::autonomous.MakeWithBuilder()
201 .run_auto(true).Send();
202 } else if (data.NegEdge(ControlBit::kEnabled)) {
203 LOG(INFO, "Stopping auto mode\n");
204 ::frc971::autonomous::autonomous.MakeWithBuilder()
205 .run_auto(false).Send();
206 }
Austin Schuh58d23682014-02-23 01:39:50 -0800207 } else {
208 HandleTeleop(data);
Brian Silverman756f9ff2014-01-17 23:40:23 -0800209 }
210 }
Austin Schuh58d23682014-02-23 01:39:50 -0800211
212 void HandleDrivetrain(const ::aos::input::driver_station::Data &data) {
213 bool is_control_loop_driving = false;
214 double left_goal = 0.0;
215 double right_goal = 0.0;
216 const double wheel = -data.GetAxis(kSteeringWheel);
217 const double throttle = -data.GetAxis(kDriveThrottle);
218 const double kThrottleGain = 1.0 / 2.5;
219 if (false && (data.IsPressed(kDriveControlLoopEnable1) ||
220 data.IsPressed(kDriveControlLoopEnable2))) {
221 // TODO(austin): Static sucks!
222 static double distance = 0.0;
223 static double angle = 0.0;
224 static double filtered_goal_distance = 0.0;
225 if (data.PosEdge(kDriveControlLoopEnable1) ||
226 data.PosEdge(kDriveControlLoopEnable2)) {
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000227 if (drivetrain.position.FetchLatest() && othersensors.FetchLatest()) {
Austin Schuh58d23682014-02-23 01:39:50 -0800228 distance = (drivetrain.position->left_encoder +
229 drivetrain.position->right_encoder) /
230 2.0 -
231 throttle * kThrottleGain / 2.0;
Ben Fredrickson81ba2d52014-03-02 08:21:46 +0000232 angle = othersensors->gyro_angle;
Austin Schuh58d23682014-02-23 01:39:50 -0800233 filtered_goal_distance = distance;
234 }
235 }
236 is_control_loop_driving = true;
237
238 // const double gyro_angle = Gyro.View().angle;
239 const double goal_theta = angle - wheel * 0.27;
240 const double goal_distance = distance + throttle * kThrottleGain;
241 const double robot_width = 22.0 / 100.0 * 2.54;
242 const double kMaxVelocity = 0.6;
243 if (goal_distance > kMaxVelocity * 0.02 + filtered_goal_distance) {
244 filtered_goal_distance += kMaxVelocity * 0.02;
245 } else if (goal_distance <
246 -kMaxVelocity * 0.02 + filtered_goal_distance) {
247 filtered_goal_distance -= kMaxVelocity * 0.02;
248 } else {
249 filtered_goal_distance = goal_distance;
250 }
251 left_goal = filtered_goal_distance - robot_width * goal_theta / 2.0;
252 right_goal = filtered_goal_distance + robot_width * goal_theta / 2.0;
253 is_high_gear_ = false;
254
255 LOG(DEBUG, "Left goal %f Right goal %f\n", left_goal, right_goal);
256 }
257 if (!drivetrain.goal.MakeWithBuilder()
258 .steering(wheel)
259 .throttle(throttle)
260 .highgear(is_high_gear_)
261 .quickturn(data.IsPressed(kQuickTurn))
262 .control_loop_driving(is_control_loop_driving)
263 .left_goal(left_goal)
264 .right_goal(right_goal)
265 .Send()) {
266 LOG(WARNING, "sending stick values failed\n");
267 }
268 if (data.PosEdge(kShiftHigh)) {
269 is_high_gear_ = false;
270 }
271 if (data.PosEdge(kShiftLow)) {
272 is_high_gear_ = true;
273 }
274 }
275
276 void SetGoal(ClawGoal goal) {
277 goal_angle_ = goal.angle;
278 separation_angle_ = goal.separation;
279 }
280
281 void HandleTeleop(const ::aos::input::driver_station::Data &data) {
282 HandleDrivetrain(data);
283
Austin Schuh9cb836e2014-02-23 19:25:55 -0800284 if (data.IsPressed(kIntakeOpenPosition)) {
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800285 action_queue_.CancelAllActions();
Austin Schuh9cb836e2014-02-23 19:25:55 -0800286 SetGoal(kIntakeOpenGoal);
287 } else if (data.IsPressed(kIntakePosition)) {
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800288 action_queue_.CancelAllActions();
Austin Schuh58d23682014-02-23 01:39:50 -0800289 SetGoal(kIntakeGoal);
290 } else if (data.IsPressed(kTuck)) {
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800291 action_queue_.CancelAllActions();
Austin Schuh58d23682014-02-23 01:39:50 -0800292 SetGoal(kTuckGoal);
293 }
294
Ben Fredricksonaa450452014-03-01 09:41:18 +0000295 if (data.PosEdge(kLongShot)) {
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800296 auto shoot_action = MakeShootAction();
297
298 shot_power_ = 160.0;
299 shoot_action->GetGoal()->shot_power = shot_power_;
300 shoot_action->GetGoal()->shot_angle = kLongShotGoal.angle;
301 SetGoal(kLongShotGoal);
302
303 action_queue_.QueueAction(::std::move(shoot_action));
Ben Fredricksonf465a062014-03-02 00:18:59 +0000304 } else if (data.PosEdge(kMediumShot)) {
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800305 auto shoot_action = MakeShootAction();
306
307 shot_power_ = 100.0;
308 shoot_action->GetGoal()->shot_power = shot_power_;
309 shoot_action->GetGoal()->shot_angle = kMediumShotGoal.angle;
310 SetGoal(kMediumShotGoal);
311
312 action_queue_.QueueAction(::std::move(shoot_action));
Ben Fredricksonf465a062014-03-02 00:18:59 +0000313 } else if (data.PosEdge(kShortShot)) {
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800314 auto shoot_action = MakeShootAction();
315
316 shot_power_ = 70.0;
317 shoot_action->GetGoal()->shot_power = shot_power_;
318 shoot_action->GetGoal()->shot_angle = kShortShotGoal.angle;
319 SetGoal(kShortShotGoal);
320
321 action_queue_.QueueAction(::std::move(shoot_action));
322 }
323
324 action_queue_.Tick();
325
326 // Send out the claw and shooter goals if no actions are running.
327 if (!action_queue_.Running()) {
328 if (!control_loops::claw_queue_group.goal.MakeWithBuilder()
329 .bottom_angle(goal_angle_)
330 .separation_angle(separation_angle_)
331 .intake(data.IsPressed(kRollersIn)
332 ? 12.0
333 : (data.IsPressed(kRollersOut) ? -12.0 : 0.0))
334 .centering(data.IsPressed(kRollersIn) ? 12.0 : 0.0)
335 .Send()) {
336 LOG(WARNING, "sending claw goal failed\n");
337 }
338
339 if (!control_loops::shooter_queue_group.goal.MakeWithBuilder()
340 .shot_power(shot_power_)
341 .shot_requested(data.IsPressed(kFire))
342 .unload_requested(data.IsPressed(kUnload))
343 .load_requested(data.IsPressed(kReload))
344 .Send()) {
345 LOG(WARNING, "sending shooter goal failed\n");
346 }
Austin Schuh58d23682014-02-23 01:39:50 -0800347 }
348 }
349
Austin Schuh01c652b2014-02-21 23:13:42 -0800350 private:
Austin Schuh58d23682014-02-23 01:39:50 -0800351 bool is_high_gear_;
352 double shot_power_;
353 double goal_angle_;
354 double separation_angle_;
Austin Schuhb7dfabc2014-03-01 18:57:42 -0800355
356 ActionQueue action_queue_;
Brian Silverman756f9ff2014-01-17 23:40:23 -0800357};
358
359} // namespace joysticks
360} // namespace input
361} // namespace frc971
362
363int main() {
364 ::aos::Init();
365 ::frc971::input::joysticks::Reader reader;
366 reader.Run();
367 ::aos::Cleanup();
368}