blob: 4c96de027959705b8c5cc128e78bdd7e95a09252 [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#include "y2018/constants.h"
8#include "y2018/control_loops/superstructure/intake/intake_delayed_plant.h"
9#include "y2018/control_loops/superstructure/intake/intake_plant.h"
10
Stephan Pleinesf63bde82024-01-13 15:59:33 -080011namespace y2018::control_loops::superstructure::intake {
Sabina Davis8d20ca82018-02-19 13:17:45 -080012
13namespace chrono = ::std::chrono;
14using ::aos::monotonic_clock;
15
16constexpr double IntakeController::kDt;
17
18IntakeController::IntakeController()
19 : loop_(new StateFeedbackLoop<5, 1, 2, double, StateFeedbackPlant<5, 1, 2>,
20 StateFeedbackObserver<5, 1, 2>>(
21 superstructure::intake::MakeDelayedIntakeLoop())),
22 intake_range_(::y2018::constants::Values::kIntakeRange()) {
23 Y_.setZero();
24}
25
26void IntakeController::set_position(double spring_angle,
27 double output_position) {
28 // Update position in the model.
29 Y_ << spring_angle, (output_position + offset_);
30}
31
32double IntakeController::voltage() const { return loop_->U(0, 0); }
33
34void IntakeController::Reset() { reset_ = true; }
35
36void IntakeController::UpdateOffset(double offset) {
37 const double doffset = offset - offset_;
38 offset_ = offset;
39
40 loop_->mutable_X_hat(0) += doffset;
41 loop_->mutable_X_hat(2) += doffset;
42}
43
44double IntakeController::goal_angle(const double *unsafe_goal) {
45 if (unsafe_goal == nullptr) {
46 return 0;
47 } else {
48 return ::aos::Clip(*unsafe_goal, intake_range_.lower, intake_range_.upper);
49 }
50}
51
52void IntakeController::Update(bool disabled, const double *unsafe_goal) {
53 if (reset_) {
54 loop_->mutable_X_hat().setZero();
55 loop_->mutable_X_hat(0) = Y_(0) + Y_(1);
56 loop_->mutable_X_hat(2) = Y_(1);
57 reset_ = false;
58 }
59
60 double goal_velocity;
61 loop_->Correct(Y_);
62
63 if (unsafe_goal == nullptr) {
64 disabled = true;
65 goal_velocity = 0.0;
66 } else {
67 goal_velocity = ::aos::Clip(
Austin Schuh17dd0892018-03-02 20:06:31 -080068 ((goal_angle(unsafe_goal) - loop_->X_hat(0, 0)) * 12.0), -16.0, 16.0);
Sabina Davis8d20ca82018-02-19 13:17:45 -080069 }
70 // Computes the goal.
71 loop_->mutable_R() << 0.0, goal_velocity, 0.0, goal_velocity,
72 (goal_velocity / (kGearRatio * kMotorVelocityConstant));
73
74 loop_->Update(disabled);
75}
76
Alex Perrycb7da4b2019-08-28 19:35:56 -070077void IntakeController::SetStatus(IntakeSideStatus::Builder *status,
Sabina Davis8d20ca82018-02-19 13:17:45 -080078 const double *unsafe_goal) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070079 status->add_goal_position(goal_angle(unsafe_goal));
80 status->add_goal_velocity(loop_->R(1, 0));
81 status->add_spring_position(loop_->X_hat(0) - loop_->X_hat(2));
82 status->add_spring_velocity(loop_->X_hat(1) - loop_->X_hat(3));
83 status->add_motor_position(loop_->X_hat(2));
84 status->add_motor_velocity(loop_->X_hat(3));
85 status->add_delayed_voltage(loop_->X_hat(4));
Sabina Davis8d20ca82018-02-19 13:17:45 -080086}
87
88IntakeSide::IntakeSide(
89 const ::frc971::constants::PotAndAbsoluteEncoderZeroingConstants
Stephan Massalta769ca22019-01-09 05:29:13 +000090 &zeroing_constants,
91 const double spring_offset)
92 : zeroing_estimator_(zeroing_constants), spring_offset_(spring_offset) {}
Sabina Davis8d20ca82018-02-19 13:17:45 -080093
94void IntakeSide::Reset() { state_ = State::UNINITIALIZED; }
95
Alex Perrycb7da4b2019-08-28 19:35:56 -070096flatbuffers::Offset<superstructure::IntakeSideStatus> IntakeSide::Iterate(
97 const double *unsafe_goal,
98 const superstructure::IntakeElasticSensors *position,
99 superstructure::IntakeVoltageT *output,
100 flatbuffers::FlatBufferBuilder *fbb) {
101 zeroing_estimator_.UpdateEstimate(*position->motor_position());
Sabina Davis8d20ca82018-02-19 13:17:45 -0800102
103 switch (state_) {
104 case State::UNINITIALIZED:
105 // Wait in the uninitialized state until the intake is initialized.
Austin Schuhf257f3c2019-10-27 21:00:43 -0700106 AOS_LOG(DEBUG, "Uninitialized, waiting for intake\n");
Sabina Davis8d20ca82018-02-19 13:17:45 -0800107 zeroing_estimator_.Reset();
108 controller_.Reset();
Stephan Massalta769ca22019-01-09 05:29:13 +0000109 spring_unwrap_.Reset();
Sabina Davis8d20ca82018-02-19 13:17:45 -0800110 state_ = State::ZEROING;
111 break;
112
113 case State::ZEROING:
114 // Zero by not moving.
115 if (zeroing_estimator_.zeroed()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700116 AOS_LOG(INFO, "Now zeroed\n");
Sabina Davis8d20ca82018-02-19 13:17:45 -0800117 controller_.UpdateOffset(zeroing_estimator_.offset());
118 state_ = State::RUNNING;
119 }
120 break;
121
122 case State::RUNNING:
123 if (!(zeroing_estimator_.zeroed())) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700124 AOS_LOG(ERROR, "Zeroing estimator is no longer zeroed\n");
Sabina Davis8d20ca82018-02-19 13:17:45 -0800125 state_ = State::UNINITIALIZED;
126 }
127 if (zeroing_estimator_.error()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700128 AOS_LOG(ERROR, "Zeroing estimator error\n");
Sabina Davis8d20ca82018-02-19 13:17:45 -0800129 state_ = State::UNINITIALIZED;
130 }
131 // ESTOP if we hit the hard limits.
Stephan Massalta769ca22019-01-09 05:29:13 +0000132 if ((controller_.motor_position()) >
133 controller_.intake_range().upper_hard ||
134 (controller_.motor_position()) <
135 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;
Stephan Massalta769ca22019-01-09 05:29:13 +0000147 controller_.set_position(spring_unwrap_.Unwrap(position->spring_angle()),
Alex Perrycb7da4b2019-08-28 19:35:56 -0700148 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);
Stephan Massalta769ca22019-01-09 05:29:13 +0000162 // Save the spring wrapped status.
163 status_builder.add_spring_wrapped(spring_unwrap_.sensor_wrapped());
Alex Perrycb7da4b2019-08-28 19:35:56 -0700164
165 controller_.SetStatus(&status_builder, unsafe_goal);
166 status_builder.add_calculated_velocity(
167 (zeroing_estimator_.offset() + position->motor_position()->encoder() -
168 intake_last_position_) /
169 controller_.kDt);
170 status_builder.add_zeroed(zeroing_estimator_.zeroed());
171 status_builder.add_estopped(estopped());
Stephan Massalta769ca22019-01-09 05:29:13 +0000172 status_builder.add_state(static_cast<int32_t>(state_));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700173 intake_last_position_ =
174 zeroing_estimator_.offset() + position->motor_position()->encoder();
175
176 return status_builder.Finish();
Sabina Davis8d20ca82018-02-19 13:17:45 -0800177}
178
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800179} // namespace y2018::control_loops::superstructure::intake