blob: 214fc6c29dae781986d091031a9a2f206166712b [file] [log] [blame]
Comran Morshed25f81a02016-01-23 13:40:10 +00001#include "y2016/control_loops/superstructure/superstructure.h"
Austin Schuh10c2d112016-02-14 13:42:28 -08002#include "y2016/control_loops/superstructure/superstructure_controls.h"
Comran Morshed25f81a02016-01-23 13:40:10 +00003
4#include "aos/common/controls/control_loops.q.h"
5#include "aos/common/logging/logging.h"
6
Austin Schuh2fc10fa2016-02-08 00:44:34 -08007#include "y2016/control_loops/superstructure/integral_intake_plant.h"
8#include "y2016/control_loops/superstructure/integral_arm_plant.h"
9
10#include "y2016/constants.h"
11
Comran Morshed25f81a02016-01-23 13:40:10 +000012namespace y2016 {
13namespace control_loops {
Austin Schuh2fc10fa2016-02-08 00:44:34 -080014namespace superstructure {
Comran Morshed25f81a02016-01-23 13:40:10 +000015
Austin Schuh2fc10fa2016-02-08 00:44:34 -080016namespace {
17constexpr double kZeroingVoltage = 4.0;
Austin Schuh2fc10fa2016-02-08 00:44:34 -080018} // namespace
19
Austin Schuh2fc10fa2016-02-08 00:44:34 -080020Superstructure::Superstructure(
21 control_loops::SuperstructureQueue *superstructure_queue)
22 : aos::controls::ControlLoop<control_loops::SuperstructureQueue>(
23 superstructure_queue) {}
24
25void Superstructure::UpdateZeroingState() {
26 // TODO(austin): Explicit state transitions instead of this.
27 // TODO(adam): Change this once we have zeroing written.
28 if (!arm_.initialized() || !intake_.initialized()) {
29 state_ = INITIALIZING;
30 } else if (!intake_.zeroed()) {
31 state_ = ZEROING_INTAKE;
32 } else if (!arm_.zeroed()) {
33 state_ = ZEROING_ARM;
34 } else {
35 state_ = RUNNING;
36 }
37}
38
39void Superstructure::RunIteration(
40 const control_loops::SuperstructureQueue::Goal *unsafe_goal,
41 const control_loops::SuperstructureQueue::Position *position,
42 control_loops::SuperstructureQueue::Output *output,
43 control_loops::SuperstructureQueue::Status *status) {
44 if (WasReset()) {
45 LOG(ERROR, "WPILib reset, restarting\n");
46 arm_.Reset();
47 intake_.Reset();
48 state_ = UNINITIALIZED;
49 }
50
51 // Bool to track if we should turn the motors on or not.
52 bool disable = output == nullptr;
53
54 arm_.Correct(position->shoulder, position->wrist);
55 intake_.Correct(position->intake);
56
57 // Zeroing will work as follows:
58 // Start with the intake. Move it towards the center. Once zeroed, move it
59 // back to the bottom. Rotate the shoulder towards the center. Once zeroed,
60 // move it up enough to rotate the wrist towards the center.
61
62 // We'll then need code to do sanity checking on values.
63
64 switch (state_) {
65 case UNINITIALIZED:
66 LOG(DEBUG, "Uninitialized\n");
67 state_ = INITIALIZING;
68 disable = true;
69 break;
70
71 case INITIALIZING:
72 LOG(DEBUG, "Waiting for accurate initial position.\n");
73 disable = true;
74 // Update state_ to accurately represent the state of the zeroing
75 // estimators.
76 UpdateZeroingState();
77 if (state_ != INITIALIZING) {
78 // Set the goals to where we are now.
79 intake_.ForceGoal(intake_.angle());
80 arm_.ForceGoal(arm_.shoulder_angle(), arm_.wrist_angle());
81 }
82 break;
83
84 case ZEROING_INTAKE:
85 case ZEROING_ARM:
86 // TODO(adam): Add your magic here.
87 state_ = RUNNING;
88 break;
89
90 case RUNNING:
91 if (unsafe_goal) {
92 arm_.AdjustProfile(unsafe_goal->max_angular_velocity_shoulder,
93 unsafe_goal->max_angular_acceleration_shoulder,
94 unsafe_goal->max_angular_velocity_wrist,
95 unsafe_goal->max_angular_acceleration_wrist);
96 intake_.AdjustProfile(unsafe_goal->max_angular_velocity_wrist,
97 unsafe_goal->max_angular_acceleration_intake);
98
99 arm_.set_unprofiled_goal(unsafe_goal->angle_shoulder,
100 unsafe_goal->angle_wrist);
101 intake_.set_unprofiled_goal(unsafe_goal->angle_intake);
102 }
103
104 // Update state_ to accurately represent the state of the zeroing
105 // estimators.
106
107 if (state_ != RUNNING && state_ != ESTOP) {
108 state_ = UNINITIALIZED;
109 }
110 break;
111
112 case ESTOP:
113 LOG(ERROR, "Estop\n");
114 disable = true;
115 break;
116 }
117
118 // ESTOP if we hit any of the limits. It is safe(ish) to hit the limits while
119 // zeroing since we use such low power.
120 if (state_ == RUNNING) {
121 // ESTOP if we hit the hard limits.
122 if ((arm_.CheckHardLimits() || intake_.CheckHardLimits()) && output) {
123 state_ = ESTOP;
124 }
125 }
126
127 // Set the voltage limits.
128 const double max_voltage = state_ == RUNNING ? 12.0 : kZeroingVoltage;
129 arm_.set_max_voltage(max_voltage, max_voltage);
130 intake_.set_max_voltage(max_voltage);
131
132 // Calculate the loops for a cycle.
133 arm_.Update(disable);
134 intake_.Update(disable);
135
136 // Write out all the voltages.
137 if (output) {
138 output->voltage_intake = intake_.intake_voltage();
139 output->voltage_shoulder = arm_.shoulder_voltage();
140 output->voltage_wrist = arm_.wrist_voltage();
141 }
142
143 // Save debug/internal state.
144 // TODO(austin): Save the voltage errors.
145 status->zeroed = state_ == RUNNING;
146
147 status->shoulder.angle = arm_.X_hat(0, 0);
148 status->shoulder.angular_velocity = arm_.X_hat(1, 0);
149 status->shoulder.goal_angle = arm_.goal(0, 0);
150 status->shoulder.goal_angular_velocity = arm_.goal(1, 0);
Austin Schuh39fd6102016-02-13 22:59:48 -0800151 status->shoulder.unprofiled_goal_angle = arm_.unprofiled_goal(0, 0);
152 status->shoulder.unprofiled_goal_angular_velocity =
153 arm_.unprofiled_goal(1, 0);
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800154 status->shoulder.estimator_state = arm_.ShoulderEstimatorState();
155
156 status->wrist.angle = arm_.X_hat(2, 0);
157 status->wrist.angular_velocity = arm_.X_hat(3, 0);
158 status->wrist.goal_angle = arm_.goal(2, 0);
159 status->wrist.goal_angular_velocity = arm_.goal(3, 0);
Austin Schuh39fd6102016-02-13 22:59:48 -0800160 status->wrist.unprofiled_goal_angle = arm_.unprofiled_goal(2, 0);
161 status->wrist.unprofiled_goal_angular_velocity = arm_.unprofiled_goal(3, 0);
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800162 status->wrist.estimator_state = arm_.WristEstimatorState();
163
164 status->intake.angle = intake_.X_hat(0, 0);
165 status->intake.angular_velocity = intake_.X_hat(1, 0);
166 status->intake.goal_angle = intake_.goal(0, 0);
167 status->intake.goal_angular_velocity = intake_.goal(1, 0);
Austin Schuh39fd6102016-02-13 22:59:48 -0800168 status->intake.unprofiled_goal_angle = intake_.unprofiled_goal(0, 0);
169 status->intake.unprofiled_goal_angular_velocity =
170 intake_.unprofiled_goal(1, 0);
Austin Schuh2fc10fa2016-02-08 00:44:34 -0800171 status->intake.estimator_state = intake_.IntakeEstimatorState();
172
173 status->estopped = (state_ == ESTOP);
174
175 status->state = state_;
176
177 last_state_ = state_;
178}
179
180} // namespace superstructure
Comran Morshed25f81a02016-01-23 13:40:10 +0000181} // namespace control_loops
182} // namespace y2016