blob: dffebbc15bc1a5eb286a9e8a418910b094609eaf [file] [log] [blame]
Sabina Davis8d20ca82018-02-19 13:17:45 -08001#include "y2018/control_loops/superstructure/intake/intake.h"
2
3#include <chrono>
4
John Park33858a32018-09-28 23:05:48 -07005#include "aos/commonmath.h"
John Park33858a32018-09-28 23:05:48 -07006#include "aos/logging/logging.h"
Sabina Davis8d20ca82018-02-19 13:17:45 -08007
8#include "y2018/constants.h"
9#include "y2018/control_loops/superstructure/intake/intake_delayed_plant.h"
10#include "y2018/control_loops/superstructure/intake/intake_plant.h"
11
12namespace y2018 {
13namespace control_loops {
14namespace superstructure {
15namespace intake {
16
17namespace chrono = ::std::chrono;
18using ::aos::monotonic_clock;
19
20constexpr double IntakeController::kDt;
21
22IntakeController::IntakeController()
23 : loop_(new StateFeedbackLoop<5, 1, 2, double, StateFeedbackPlant<5, 1, 2>,
24 StateFeedbackObserver<5, 1, 2>>(
25 superstructure::intake::MakeDelayedIntakeLoop())),
26 intake_range_(::y2018::constants::Values::kIntakeRange()) {
27 Y_.setZero();
28}
29
30void IntakeController::set_position(double spring_angle,
31 double output_position) {
32 // Update position in the model.
33 Y_ << spring_angle, (output_position + offset_);
34}
35
36double IntakeController::voltage() const { return loop_->U(0, 0); }
37
38void IntakeController::Reset() { reset_ = true; }
39
40void IntakeController::UpdateOffset(double offset) {
41 const double doffset = offset - offset_;
42 offset_ = offset;
43
44 loop_->mutable_X_hat(0) += doffset;
45 loop_->mutable_X_hat(2) += doffset;
46}
47
48double IntakeController::goal_angle(const double *unsafe_goal) {
49 if (unsafe_goal == nullptr) {
50 return 0;
51 } else {
52 return ::aos::Clip(*unsafe_goal, intake_range_.lower, intake_range_.upper);
53 }
54}
55
56void IntakeController::Update(bool disabled, const double *unsafe_goal) {
57 if (reset_) {
58 loop_->mutable_X_hat().setZero();
59 loop_->mutable_X_hat(0) = Y_(0) + Y_(1);
60 loop_->mutable_X_hat(2) = Y_(1);
61 reset_ = false;
62 }
63
64 double goal_velocity;
65 loop_->Correct(Y_);
66
67 if (unsafe_goal == nullptr) {
68 disabled = true;
69 goal_velocity = 0.0;
70 } else {
71 goal_velocity = ::aos::Clip(
Austin Schuh17dd0892018-03-02 20:06:31 -080072 ((goal_angle(unsafe_goal) - loop_->X_hat(0, 0)) * 12.0), -16.0, 16.0);
Sabina Davis8d20ca82018-02-19 13:17:45 -080073 }
74 // Computes the goal.
75 loop_->mutable_R() << 0.0, goal_velocity, 0.0, goal_velocity,
76 (goal_velocity / (kGearRatio * kMotorVelocityConstant));
77
78 loop_->Update(disabled);
79}
80
Alex Perrycb7da4b2019-08-28 19:35:56 -070081void IntakeController::SetStatus(IntakeSideStatus::Builder *status,
Sabina Davis8d20ca82018-02-19 13:17:45 -080082 const double *unsafe_goal) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070083 status->add_goal_position(goal_angle(unsafe_goal));
84 status->add_goal_velocity(loop_->R(1, 0));
85 status->add_spring_position(loop_->X_hat(0) - loop_->X_hat(2));
86 status->add_spring_velocity(loop_->X_hat(1) - loop_->X_hat(3));
87 status->add_motor_position(loop_->X_hat(2));
88 status->add_motor_velocity(loop_->X_hat(3));
89 status->add_delayed_voltage(loop_->X_hat(4));
Sabina Davis8d20ca82018-02-19 13:17:45 -080090}
91
92IntakeSide::IntakeSide(
93 const ::frc971::constants::PotAndAbsoluteEncoderZeroingConstants
94 &zeroing_constants)
95 : zeroing_estimator_(zeroing_constants) {}
96
97void IntakeSide::Reset() { state_ = State::UNINITIALIZED; }
98
Alex Perrycb7da4b2019-08-28 19:35:56 -070099flatbuffers::Offset<superstructure::IntakeSideStatus> IntakeSide::Iterate(
100 const double *unsafe_goal,
101 const superstructure::IntakeElasticSensors *position,
102 superstructure::IntakeVoltageT *output,
103 flatbuffers::FlatBufferBuilder *fbb) {
104 zeroing_estimator_.UpdateEstimate(*position->motor_position());
Sabina Davis8d20ca82018-02-19 13:17:45 -0800105
106 switch (state_) {
107 case State::UNINITIALIZED:
108 // Wait in the uninitialized state until the intake is initialized.
Austin Schuhf257f3c2019-10-27 21:00:43 -0700109 AOS_LOG(DEBUG, "Uninitialized, waiting for intake\n");
Sabina Davis8d20ca82018-02-19 13:17:45 -0800110 zeroing_estimator_.Reset();
111 controller_.Reset();
112 state_ = State::ZEROING;
113 break;
114
115 case State::ZEROING:
116 // Zero by not moving.
117 if (zeroing_estimator_.zeroed()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700118 AOS_LOG(INFO, "Now zeroed\n");
Sabina Davis8d20ca82018-02-19 13:17:45 -0800119 controller_.UpdateOffset(zeroing_estimator_.offset());
120 state_ = State::RUNNING;
121 }
122 break;
123
124 case State::RUNNING:
125 if (!(zeroing_estimator_.zeroed())) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700126 AOS_LOG(ERROR, "Zeroing estimator is no longer zeroed\n");
Sabina Davis8d20ca82018-02-19 13:17:45 -0800127 state_ = State::UNINITIALIZED;
128 }
129 if (zeroing_estimator_.error()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700130 AOS_LOG(ERROR, "Zeroing estimator error\n");
Sabina Davis8d20ca82018-02-19 13:17:45 -0800131 state_ = State::UNINITIALIZED;
132 }
133 // ESTOP if we hit the hard limits.
Alex Perrycb7da4b2019-08-28 19:35:56 -0700134 if ((controller_.motor_position()) > controller_.intake_range().upper_hard ||
135 (controller_.motor_position()) < controller_.intake_range().lower_hard) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700136 AOS_LOG(ERROR, "Hit hard limits\n");
Sabina Davis8d20ca82018-02-19 13:17:45 -0800137 state_ = State::ESTOP;
138 }
139 break;
140
141 case State::ESTOP:
Austin Schuhf257f3c2019-10-27 21:00:43 -0700142 AOS_LOG(ERROR, "Estop\n");
Sabina Davis8d20ca82018-02-19 13:17:45 -0800143 break;
144 }
145
146 const bool disable = (output == nullptr) || state_ != State::RUNNING;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700147 controller_.set_position(position->spring_angle(),
148 position->motor_position()->encoder());
Sabina Davis8d20ca82018-02-19 13:17:45 -0800149
150 controller_.Update(disable, unsafe_goal);
151
152 if (output) {
153 output->voltage_elastic = controller_.voltage();
154 }
155
Alex Perrycb7da4b2019-08-28 19:35:56 -0700156 flatbuffers::Offset<frc971::PotAndAbsoluteEncoderEstimatorState>
157 estimator_state = zeroing_estimator_.GetEstimatorState(fbb);
158
159 superstructure::IntakeSideStatus::Builder status_builder(*fbb);
Sabina Davis8d20ca82018-02-19 13:17:45 -0800160 // Save debug/internal state.
Alex Perrycb7da4b2019-08-28 19:35:56 -0700161 status_builder.add_estimator_state(estimator_state);
162
163 controller_.SetStatus(&status_builder, unsafe_goal);
164 status_builder.add_calculated_velocity(
165 (zeroing_estimator_.offset() + position->motor_position()->encoder() -
166 intake_last_position_) /
167 controller_.kDt);
168 status_builder.add_zeroed(zeroing_estimator_.zeroed());
169 status_builder.add_estopped(estopped());
170 status_builder.add_state ( static_cast<int32_t>(state_));
171 intake_last_position_ =
172 zeroing_estimator_.offset() + position->motor_position()->encoder();
173
174 return status_builder.Finish();
Sabina Davis8d20ca82018-02-19 13:17:45 -0800175}
176
177} // namespace intake
178} // namespace superstructure
179} // namespace control_loops
180} // namespace y2018