blob: 8c35733d76b6d866ce24b8671dc5cecb99d63355 [file] [log] [blame]
Austin Schuh3bb9a442014-02-02 16:01:45 -08001#include "frc971/control_loops/claw/claw.h"
2
3#include <stdio.h>
4
5#include <algorithm>
6
7#include "aos/common/control_loop/control_loops.q.h"
8#include "aos/common/logging/logging.h"
9
10#include "frc971/constants.h"
11#include "frc971/control_loops/claw/top_claw_motor_plant.h"
12#include "frc971/control_loops/claw/bottom_claw_motor_plant.h"
13
14// Zeroing plan.
15// There are 2 types of zeros. Enabled and disabled ones.
16// Disabled ones are only valid during auto mode, and can be used to speed up
17// the enabled zero process. We need to re-zero during teleop in case the auto
18// zero was poor and causes us to miss all our shots.
19//
20// We need to be able to zero manually while disabled by moving the joint over
21// the zeros.
22// Zero on the down edge when disabled (gravity in the direction of motion)
23//
24// When enabled, zero on the up edge (gravity opposing the direction of motion)
25// The enabled sequence needs to work as follows. We can crash the claw if we
26// bring them too close to each other or too far from each other. The only safe
27// thing to do is to move them in unison.
28//
29// Start by moving them both towards the front of the bot to either find either
30// the middle hall effect on either jaw, or the front hall effect on the bottom
31// jaw. Any edge that isn't the desired edge will provide an approximate edge
32// location that can be used for the fine tuning step.
33// Once an edge is found on the front claw, move back the other way with both
34// claws until an edge is found for the other claw.
35// Now that we have an approximate zero, we can robustify the limits to keep
36// both claws safe. Then, we can move both claws to a position that is the
37// correct side of the zero and go zero.
38
39// Valid region plan.
40// Difference between the arms has a range, and the values of each arm has a range.
41// If a claw runs up against a static limit, don't let the goal change outside
42// the limit.
43// If a claw runs up against a movable limit, move both claws outwards to get
44// out of the condition.
45
46namespace frc971 {
47namespace control_loops {
48
Austin Schuh4b7b5d02014-02-10 21:20:34 -080049void ZeroedStateFeedbackLoop::CapU() {
50 const double old_voltage = voltage_;
51 voltage_ += U(0, 0);
52
53 uncapped_voltage_ = voltage_;
54
Austin Schuhf9286cd2014-02-11 00:51:09 -080055 double limit = zeroing_state() != UNKNOWN_POSITION ? 12.0 : kZeroingMaxVoltage;
Austin Schuh4b7b5d02014-02-10 21:20:34 -080056
57 // Make sure that reality and the observer can't get too far off. There is a
58 // delay by one cycle between the applied voltage and X_hat(2, 0), so compare
59 // against last cycle's voltage.
60 if (X_hat(2, 0) > last_voltage_ + 2.0) {
61 voltage_ -= X_hat(2, 0) - (last_voltage_ + 2.0);
62 LOG(DEBUG, "X_hat(2, 0) = %f\n", X_hat(2, 0));
63 } else if (X_hat(2, 0) < last_voltage_ -2.0) {
64 voltage_ += X_hat(2, 0) - (last_voltage_ - 2.0);
65 LOG(DEBUG, "X_hat(2, 0) = %f\n", X_hat(2, 0));
66 }
67
68 voltage_ = std::min(limit, voltage_);
69 voltage_ = std::max(-limit, voltage_);
70 U(0, 0) = voltage_ - old_voltage;
Austin Schuhf9286cd2014-02-11 00:51:09 -080071 LOG(DEBUG, "abc %f\n", X_hat(2, 0) - voltage_);
72 LOG(DEBUG, "error %f\n", X_hat(0, 0) - R(0, 0));
Austin Schuh4b7b5d02014-02-10 21:20:34 -080073
74 last_voltage_ = voltage_;
75}
76
Austin Schuhcc0bf312014-02-09 00:39:29 -080077ClawMotor::ClawMotor(control_loops::ClawGroup *my_claw)
78 : aos::control_loops::ControlLoop<control_loops::ClawGroup>(my_claw),
Austin Schuh4b7b5d02014-02-10 21:20:34 -080079 has_top_claw_goal_(false),
80 top_claw_goal_(0.0),
81 top_claw_(MakeTopClawLoop()),
82 has_bottom_claw_goal_(false),
83 bottom_claw_goal_(0.0),
84 bottom_claw_(MakeBottomClawLoop()),
85 was_enabled_(false) {}
Austin Schuh3bb9a442014-02-02 16:01:45 -080086
Austin Schuh4b7b5d02014-02-10 21:20:34 -080087const int ZeroedStateFeedbackLoop::kZeroingMaxVoltage;
Austin Schuh3bb9a442014-02-02 16:01:45 -080088
Austin Schuhf9286cd2014-02-11 00:51:09 -080089bool ZeroedStateFeedbackLoop::GetPositionOfEdge(
90 const constants::Values::Claw &claw_values, double *edge_encoder,
91 double *edge_angle) {
92
93 // TODO(austin): Validate that the hall effect edge makes sense.
94 // We must now be on the side of the edge that we expect to be, and the
95 // encoder must have been on either side of the edge before and after.
96
97 if (front_hall_effect_posedge_count_changed()) {
98 if (encoder() - last_encoder() < 0) {
99 *edge_angle = claw_values.front.upper_angle;
100 } else {
101 *edge_angle = claw_values.front.lower_angle;
102 }
103 *edge_encoder = posedge_value_;
104 return true;
105 }
106 if (front_hall_effect_negedge_count_changed()) {
107 if (encoder() - last_encoder() > 0) {
108 *edge_angle = claw_values.front.upper_angle;
109 } else {
110 *edge_angle = claw_values.front.lower_angle;
111 }
112 *edge_encoder = negedge_value_;
113 return true;
114 }
115 if (calibration_hall_effect_posedge_count_changed()) {
116 if (encoder() - last_encoder() < 0) {
117 *edge_angle = claw_values.calibration.upper_angle;
118 } else {
119 *edge_angle = claw_values.calibration.lower_angle;
120 }
121 *edge_encoder = posedge_value_;
122 return true;
123 }
124 if (calibration_hall_effect_negedge_count_changed()) {
125 if (encoder() - last_encoder() > 0) {
126 *edge_angle = claw_values.calibration.upper_angle;
127 } else {
128 *edge_angle = claw_values.calibration.lower_angle;
129 }
130 *edge_encoder = negedge_value_;
131 return true;
132 }
133 if (back_hall_effect_posedge_count_changed()) {
134 if (encoder() - last_encoder() < 0) {
135 *edge_angle = claw_values.back.upper_angle;
136 } else {
137 *edge_angle = claw_values.back.lower_angle;
138 }
139 *edge_encoder = posedge_value_;
140 return true;
141 }
142 if (back_hall_effect_negedge_count_changed()) {
143 if (encoder() - last_encoder() > 0) {
144 *edge_angle = claw_values.back.upper_angle;
145 } else {
146 *edge_angle = claw_values.back.lower_angle;
147 }
148 *edge_encoder = negedge_value_;
149 return true;
150 }
151 return false;
152}
153
Austin Schuh3bb9a442014-02-02 16:01:45 -0800154// Positive angle is up, and positive power is up.
Austin Schuhcc0bf312014-02-09 00:39:29 -0800155void ClawMotor::RunIteration(const control_loops::ClawGroup::Goal *goal,
156 const control_loops::ClawGroup::Position *position,
157 control_loops::ClawGroup::Output *output,
Austin Schuh3bb9a442014-02-02 16:01:45 -0800158 ::aos::control_loops::Status *status) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800159 constexpr double dt = 0.01;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800160
161 // Disable the motors now so that all early returns will return with the
162 // motors disabled.
163 if (output) {
164 output->top_claw_voltage = 0;
165 output->bottom_claw_voltage = 0;
166 output->intake_voltage = 0;
167 }
168
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800169 // TODO(austin): Handle the disabled state and the disabled -> enabled
170 // transition in all of these states.
171 // TODO(austin): Handle zeroing while disabled.
172
173 // TODO(austin): Save all the counters so we know when something actually
174 // happens.
175 // TODO(austin): Helpers to find the position of the claw on an edge.
176
177 // TODO(austin): This may not be necesary because of the ControlLoop class.
178 ::aos::robot_state.FetchLatest();
179 if (::aos::robot_state.get() == nullptr) {
180 return;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800181 }
182
Austin Schuhf9286cd2014-02-11 00:51:09 -0800183 const frc971::constants::Values &values = constants::GetValues();
184
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800185 if (position) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800186 top_claw_.SetPositionValues(position->top);
187 bottom_claw_.SetPositionValues(position->bottom);
188
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800189 if (!has_top_claw_goal_) {
190 has_top_claw_goal_ = true;
191 top_claw_goal_ = position->top.position;
192 }
193 if (!has_bottom_claw_goal_) {
194 has_bottom_claw_goal_ = true;
195 bottom_claw_goal_ = position->bottom.position;
196 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800197 }
198
199 bool autonomous = ::aos::robot_state->autonomous;
Austin Schuhf9286cd2014-02-11 00:51:09 -0800200 bool enabled = ::aos::robot_state->enabled;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800201
202 if ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
203 bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
204 (autonomous &&
205 ((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
206 top_claw_.zeroing_state() ==
207 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
208 (bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
209 bottom_claw_.zeroing_state() ==
210 ZeroedStateFeedbackLoop::DISABLED_CALIBRATION)))) {
211 // Ready to use the claw.
212 // Limit the goals here.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800213 bottom_claw_goal_ = goal->bottom_angle;
214 top_claw_goal_ = goal->bottom_angle + goal->seperation_angle;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800215 } else if (top_claw_.zeroing_state() !=
216 ZeroedStateFeedbackLoop::UNKNOWN_POSITION &&
217 bottom_claw_.zeroing_state() !=
218 ZeroedStateFeedbackLoop::UNKNOWN_POSITION) {
219 // Time to fine tune the zero.
220 // Limit the goals here.
221 if (bottom_claw_.zeroing_state() != ZeroedStateFeedbackLoop::CALIBRATED) {
222 } else {
223 }
224 } else {
225 if (!was_enabled_ && enabled) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800226 if (position) {
227 top_claw_goal_ = position->top.position;
228 bottom_claw_goal_ = position->bottom.position;
229 } else {
230 has_top_claw_goal_ = false;
231 has_bottom_claw_goal_ = false;
232 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800233 }
Austin Schuhf9286cd2014-02-11 00:51:09 -0800234
235 // TODO(austin): Limit the goals here.
236 // Need to prevent windup, limit voltage, deal with windup on only 1 claw,
237 // ...
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800238 if (top_claw_.zeroing_state() ==
239 ZeroedStateFeedbackLoop::UNKNOWN_POSITION) {
240 }
241 if (bottom_claw_.zeroing_state() ==
242 ZeroedStateFeedbackLoop::UNKNOWN_POSITION) {
243 }
244
245 if (bottom_claw_.zeroing_state() !=
246 ZeroedStateFeedbackLoop::UNKNOWN_POSITION) {
Austin Schuhf9286cd2014-02-11 00:51:09 -0800247 if (enabled) {
248 // Time to slowly move back up to find any position to narrow down the
249 // zero.
250 top_claw_goal_ += values.claw_zeroing_off_speed * dt;
251 bottom_claw_goal_ += values.claw_zeroing_off_speed * dt;
252 // TODO(austin): Goal velocity too!
253 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800254 } else {
255 // We don't know where either claw is. Slowly start moving down to find
256 // any hall effect.
Austin Schuhf9286cd2014-02-11 00:51:09 -0800257 if (enabled) {
258 top_claw_goal_-= values.claw_zeroing_off_speed * dt;
259 bottom_claw_goal_ -= values.claw_zeroing_off_speed * dt;
260 // TODO(austin): Goal velocity too!
261 }
262 }
263
264 if (enabled) {
265 top_claw_.SetCalibrationOnEdge(
266 values.upper_claw, ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
267 bottom_claw_.SetCalibrationOnEdge(
268 values.lower_claw, ZeroedStateFeedbackLoop::APPROXIMATE_CALIBRATION);
269 } else {
270 top_claw_.SetCalibrationOnEdge(
271 values.upper_claw, ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
272 bottom_claw_.SetCalibrationOnEdge(
273 values.lower_claw, ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800274 }
275 }
276
277 // TODO(austin): Handle disabled.
Austin Schuh3bb9a442014-02-02 16:01:45 -0800278
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800279 // TODO(austin): ...
Austin Schuhf9286cd2014-02-11 00:51:09 -0800280 if (has_top_claw_goal_ && has_bottom_claw_goal_) {
281 top_claw_.R << top_claw_goal_, 0.0, 0.0;
282 bottom_claw_.R << bottom_claw_goal_, 0.0, 0.0;
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800283
Austin Schuhf9286cd2014-02-11 00:51:09 -0800284 top_claw_.Update(output == nullptr);
285 bottom_claw_.Update(output == nullptr);
286 } else {
287 top_claw_.ZeroPower();
288 bottom_claw_.ZeroPower();
289 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800290
291 if (position) {
292 //LOG(DEBUG, "pos: %f hall: %s absolute: %f\n", position->top_position,
293 //position->top_calibration_hall_effect ? "true" : "false",
294 //zeroed_joint_.absolute_position());
Austin Schuh3bb9a442014-02-02 16:01:45 -0800295 }
296
297 if (output) {
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800298 output->top_claw_voltage = top_claw_.voltage();
299 output->bottom_claw_voltage = bottom_claw_.voltage();
Austin Schuh3bb9a442014-02-02 16:01:45 -0800300 }
Austin Schuh4b7b5d02014-02-10 21:20:34 -0800301 status->done = false;
302 //::std::abs(zeroed_joint_.absolute_position() - goal->bottom_angle -
303 //goal->seperation_angle) < 0.004;
304
305 was_enabled_ = ::aos::robot_state->enabled;
Austin Schuh3bb9a442014-02-02 16:01:45 -0800306}
307
308} // namespace control_loops
309} // namespace frc971