blob: 73da9b9f13eee1a1cd1612e45fdb30daef88b329 [file] [log] [blame]
Austin Schuhd5ccb862017-03-11 22:06:36 -08001#ifndef Y2017_CONTROL_LOOPS_SUPERSTRUCTURE_COLUMN_COLUMN_H_
2#define Y2017_CONTROL_LOOPS_SUPERSTRUCTURE_COLUMN_COLUMN_H_
3
4#include <array>
5#include <chrono>
6#include <memory>
7#include <utility>
8
9#include "Eigen/Dense"
10
11#include "frc971/constants.h"
12#include "frc971/control_loops/profiled_subsystem.h"
13#include "frc971/control_loops/state_feedback_loop.h"
14#include "y2017/constants.h"
15#include "y2017/control_loops/superstructure/column/column_zeroing.h"
16#include "y2017/control_loops/superstructure/intake/intake.h"
17#include "y2017/control_loops/superstructure/superstructure.q.h"
Austin Schuhac76bb32017-03-22 22:34:26 -070018#include "y2017/control_loops/superstructure/vision_time_adjuster.h"
Philipp Schrader8e3ac0f2017-04-09 23:36:17 +000019#include "y2017/vision/vision.q.h"
Austin Schuhd5ccb862017-03-11 22:06:36 -080020
21namespace y2017 {
22namespace control_loops {
23namespace superstructure {
24namespace column {
25
26class ColumnProfiledSubsystem
27 : public ::frc971::control_loops::ProfiledSubsystem<
28 6, 1, ColumnZeroingEstimator, 2, 2> {
29 public:
30 ColumnProfiledSubsystem(
31 ::std::unique_ptr<
32 ::frc971::control_loops::SimpleCappedStateFeedbackLoop<6, 2, 2>>
33 loop,
34 const ::y2017::constants::Values::Column &zeroing_constants,
35 const ::frc971::constants::Range &range, double default_angular_velocity,
36 double default_angular_acceleration);
37
38 // Updates our estimator with the latest position.
39 void Correct(const ColumnPosition &position);
40 // Runs the controller and profile generator for a cycle.
41 void Update(bool disabled);
42
43 // Fills out the ProfiledJointStatus structure with the current state.
44 template <class StatusType>
45 void PopulateTurretStatus(StatusType *status);
46
47 // Forces the current goal to the provided goal, bypassing the profiler.
48 void ForceGoal(double goal_velocity, double goal);
49 // Sets the unprofiled goal. The profiler will generate a profile to go to
50 // this goal.
51 void set_indexer_unprofiled_goal(double goal_velocity);
52 void set_turret_unprofiled_goal(double unprofiled_goal);
53 void set_unprofiled_goal(double goal_velocity, double unprofiled_goal);
54 // Limits our profiles to a max velocity and acceleration for proper motion.
55 void AdjustProfile(const ::frc971::ProfileParameters &profile_parameters);
56 void AdjustProfile(double max_angular_velocity,
57 double max_angular_acceleration);
58
59 // Returns true if we have exceeded any hard limits.
60 bool CheckHardLimits();
61
62 // Returns the requested voltage.
63 double indexer_voltage() const { return loop_->U(0, 0); }
64 double uncapped_indexer_voltage() const { return loop_->U_uncapped(0, 0); }
65 double turret_voltage() const { return loop_->U(1, 0); }
66
67 // Returns the current Y.
68 const ::Eigen::Matrix<double, 2, 1> Y() const { return Y_; }
69 double Y(int i, int j) const { return Y_(i, j); }
70
71 // Returns the current indexer position.
72 double indexer_position() const { return Y_(0, 0); }
73
74 bool saturated() const { return saturated_; }
75
76 // Returns the current turret position.
77 double turret_position() const { return Y_(1, 0) + Y_(0, 0); }
78
79 // For testing:
80 // Triggers an estimator error.
81 void TriggerEstimatorError() { estimators_[0].TriggerError(); }
82
83 const ::frc971::constants::Range &range() const { return range_; }
84
85 bool IsIndexerStuck() const;
86 double IndexerStuckVoltage() const;
87 void PartialIndexerReset();
88 void PartialTurretReset();
89 void PopulateIndexerStatus(IndexerStatus *status);
90
91 void AddOffset(double indexer_offset_delta, double turret_offset_delta);
92
93 protected:
94 // Limits the provided goal to the soft limits. Prints "name" when it fails
95 // to aid debugging.
96 virtual void CapGoal(const char *name, Eigen::Matrix<double, 6, 1> *goal);
97
98 private:
99 void UpdateOffset(double indexer_offset, double turret_offset);
100
101 ::std::unique_ptr<StateFeedbackLoop<6, 2, 2>> stuck_indexer_detector_;
102
103 // History array for calculating a filtered angular velocity.
104 static constexpr int kHistoryLength = 5;
105 ::std::array<double, kHistoryLength> indexer_history_;
106 ptrdiff_t indexer_history_position_ = 0;
107
108 double indexer_error_ = 0.0;
109 double indexer_dt_velocity_ = 0.0;
110 double indexer_last_position_ = 0.0;
111 double indexer_average_angular_velocity_ = 0.0;
112 double indexer_position_error_ = 0.0;
113 bool indexer_ready_ = false;
114
115 bool saturated_ = false;
116
117 Eigen::Matrix<double, 6, 1> X_hat_current_;
118 Eigen::Matrix<double, 6, 1> stuck_indexer_X_hat_current_;
119
120 aos::util::TrapezoidProfile profile_;
121
122 // Current measurement.
123 Eigen::Matrix<double, 2, 1> Y_;
124 // Current offset. Y_ = offset_ + raw_sensor;
125 Eigen::Matrix<double, 2, 1> offset_;
126
127 const ::frc971::constants::Range range_;
128
129 const double default_velocity_;
130 const double default_acceleration_;
131
132 double turret_last_position_ = 0;
133};
134
135template <typename StatusType>
136void ColumnProfiledSubsystem::PopulateTurretStatus(StatusType *status) {
137 status->zeroed = zeroed();
138 status->state = -1;
139 // We don't know, so default to the bad case.
140 status->estopped = true;
141
142 status->position = X_hat(2, 0);
143 status->velocity = X_hat(3, 0);
144 status->goal_position = goal(2, 0);
145 status->goal_velocity = goal(3, 0);
146 status->unprofiled_goal_position = unprofiled_goal(2, 0);
147 status->unprofiled_goal_velocity = unprofiled_goal(3, 0);
148 status->voltage_error = X_hat(5, 0);
149 status->calculated_velocity =
150 (turret_position() - turret_last_position_) /
151 ::std::chrono::duration_cast<::std::chrono::duration<double>>(
152 ::aos::controls::kLoopFrequency)
153 .count();
154
155 status->estimator_state = EstimatorState(0);
156
157 Eigen::Matrix<double, 6, 1> error = controller().error();
158 status->position_power = controller().controller().K(0, 0) * error(0, 0);
159 status->velocity_power = controller().controller().K(0, 1) * error(1, 0);
160}
161
162class Column {
163 public:
164 Column();
165 double goal(int row, int col) const {
166 return profiled_subsystem_.goal(row, col);
167 }
168
169 double turret_position() const {
170 return profiled_subsystem_.turret_position();
171 }
172
173 void set_freeze(bool freeze) { freeze_ = freeze; }
174
175 // The zeroing and operating voltages.
176 static constexpr double kZeroingVoltage = 5.0;
177 static constexpr double kOperatingVoltage = 12.0;
178 static constexpr double kIntakeZeroingMinDistance = 0.08;
179 static constexpr double kIntakeTolerance = 0.005;
180 static constexpr double kStuckZeroingTrackingError = 0.02;
Austin Schuh3ae47432017-04-16 19:15:46 -0700181 static constexpr double kTurretMin = -0.1;
182 static constexpr double kTurretMax = M_PI / 2.0 + 0.1;
Austin Schuhd5ccb862017-03-11 22:06:36 -0800183
184 void Iterate(const control_loops::IndexerGoal *unsafe_indexer_goal,
185 const control_loops::TurretGoal *unsafe_turret_goal,
Philipp Schrader8e3ac0f2017-04-09 23:36:17 +0000186 const ColumnPosition *position,
187 const vision::VisionStatus *vision_status,
188 double *indexer_output, double *turret_output,
189 IndexerStatus *indexer_status,
Austin Schuhd5ccb862017-03-11 22:06:36 -0800190 TurretProfiledSubsystemStatus *turret_status,
191 intake::Intake *intake);
192
193 void Reset();
194
195 enum class State : int32_t {
196 UNINITIALIZED = 0,
197 ZEROING_UNINITIALIZED = 1,
198 ZEROING_POSITIVE = 2,
199 ZEROING_NEGATIVE = 3,
200 RUNNING = 4,
201 ESTOP = 5,
202 };
203
204 enum class IndexerState : int32_t {
205 // The system is running correctly, no stuck condition detected.
206 RUNNING = 0,
207 // The system is reversing to unjam.
208 REVERSING = 1
209 };
210
211 State state() const { return state_; }
212 IndexerState indexer_state() const { return indexer_state_; }
213
214 private:
215 State state_ = State::UNINITIALIZED;
216
217 IndexerState indexer_state_ = IndexerState::RUNNING;
218
219 bool freeze_ = false;
220
Austin Schuhac76bb32017-03-22 22:34:26 -0700221 VisionTimeAdjuster vision_time_adjuster_;
222
Austin Schuhd5ccb862017-03-11 22:06:36 -0800223 // The last time that we transitioned from RUNNING to REVERSING or the
224 // reverse. Used to implement the timeouts.
225 ::aos::monotonic_clock::time_point last_transition_time_ =
226 ::aos::monotonic_clock::min_time;
227
228 ColumnProfiledSubsystem profiled_subsystem_;
Austin Schuh25db1262017-04-05 19:39:55 -0700229
230 const double vision_error_;
Austin Schuhd5ccb862017-03-11 22:06:36 -0800231};
232
233} // namespace column
234} // namespace superstructure
235} // namespace control_loops
236} // namespace y2017
237
238#endif // Y2017_CONTROL_LOOPS_SUPERSTRUCTURE_COLUMN_COLUMN_H_