blob: 5e443dcf6667ac63bf943307b9349ab3a1da1cb4 [file] [log] [blame]
Austin Schuh473a5652017-02-05 01:30:42 -08001#ifndef FRC971_CONTROL_LOOPS_PROFILED_SUBSYSTEM_H_
2#define FRC971_CONTROL_LOOPS_PROFILED_SUBSYSTEM_H_
3
4#include <array>
5#include <memory>
6#include <utility>
7
8#include "Eigen/Dense"
9
10#include "aos/common/controls/control_loop.h"
11#include "aos/common/util/trapezoid_profile.h"
12#include "frc971/control_loops/simple_capped_state_feedback_loop.h"
13#include "frc971/control_loops/state_feedback_loop.h"
14#include "frc971/zeroing/zeroing.h"
15
16namespace frc971 {
17namespace control_loops {
18
19template <int number_of_states, int number_of_axes>
20class ProfiledSubsystem {
21 public:
22 ProfiledSubsystem(
23 ::std::unique_ptr<::frc971::control_loops::SimpleCappedStateFeedbackLoop<
Tyler Chatowf8f03112017-02-05 14:31:34 -080024 number_of_states, number_of_axes, number_of_axes>> loop,
25 ::std::array<::frc971::zeroing::PotAndIndexPulseZeroingEstimator,
26 number_of_axes> &&estimators)
Austin Schuh473a5652017-02-05 01:30:42 -080027 : loop_(::std::move(loop)), estimators_(::std::move(estimators)) {
28 zeroed_.fill(false);
29 unprofiled_goal_.setZero();
30 }
31
32 // Returns whether an error has occured
33 bool error() const {
34 for (const auto &estimator : estimators_) {
35 if (estimator.error()) {
36 return true;
37 }
38 }
39 return false;
40 }
41
42 void Reset() {
43 zeroed_.fill(false);
44 for (auto &estimator : estimators_) {
45 estimator.Reset();
46 }
47 }
48
49 // Returns the controller.
Tyler Chatowf8f03112017-02-05 14:31:34 -080050 const StateFeedbackLoop<number_of_states, number_of_axes, number_of_axes> &
51 controller() const {
Austin Schuh473a5652017-02-05 01:30:42 -080052 return *loop_;
53 }
54
55 int controller_index() const { return loop_->controller_index(); }
56
57 // Returns whether the estimators have been initialized and zeroed.
58 bool initialized() const { return initialized_; }
59
60 bool zeroed() const {
61 for (int i = 0; i < number_of_axes; ++i) {
62 if (!zeroed_[i]) {
63 return false;
64 }
65 }
66 return true;
67 }
68
69 bool zeroed(int index) const { return zeroed_[index]; };
70
71 // Returns the filtered goal.
72 const Eigen::Matrix<double, number_of_states, 1> &goal() const {
73 return loop_->R();
74 }
75 double goal(int row, int col) const { return loop_->R(row, col); }
76
77 // Returns the unprofiled goal.
78 const Eigen::Matrix<double, number_of_states, 1> &unprofiled_goal() const {
79 return unprofiled_goal_;
80 }
81 double unprofiled_goal(int row, int col) const {
82 return unprofiled_goal_(row, col);
83 }
84
85 // Returns the current state estimate.
86 const Eigen::Matrix<double, number_of_states, 1> &X_hat() const {
87 return loop_->X_hat();
88 }
89 double X_hat(int row, int col) const { return loop_->X_hat(row, col); }
90
91 // Returns the current internal estimator state for logging.
92 ::frc971::EstimatorState EstimatorState(int index) {
93 ::frc971::EstimatorState estimator_state;
94 ::frc971::zeroing::PopulateEstimatorState(estimators_[index],
95 &estimator_state);
96
97 return estimator_state;
98 }
99
100 // Sets the maximum voltage that will be commanded by the loop.
101 void set_max_voltage(::std::array<double, number_of_axes> voltages) {
102 for (int i = 0; i < number_of_axes; ++i) {
103 loop_->set_max_voltage(i, voltages[i]);
104 }
105 }
106
107 protected:
108 void set_zeroed(int index, bool val) { zeroed_[index] = val; }
109
110 // TODO(austin): It's a bold assumption to assume that we will have the same
111 // number of sensors as axes. So far, that's been fine.
112 ::std::unique_ptr<::frc971::control_loops::SimpleCappedStateFeedbackLoop<
Tyler Chatowf8f03112017-02-05 14:31:34 -0800113 number_of_states, number_of_axes, number_of_axes>> loop_;
Austin Schuh473a5652017-02-05 01:30:42 -0800114
115 // The goal that the profile tries to reach.
116 Eigen::Matrix<double, number_of_states, 1> unprofiled_goal_;
117
118 bool initialized_ = false;
119
Tyler Chatowf8f03112017-02-05 14:31:34 -0800120 ::std::array<::frc971::zeroing::PotAndIndexPulseZeroingEstimator,
121 number_of_axes> estimators_;
Austin Schuh473a5652017-02-05 01:30:42 -0800122
123 private:
124 ::std::array<bool, number_of_axes> zeroed_;
125};
126
127class SingleDOFProfiledSubsystem
128 : public ::frc971::control_loops::ProfiledSubsystem<3, 1> {
129 public:
130 SingleDOFProfiledSubsystem(
131 ::std::unique_ptr<SimpleCappedStateFeedbackLoop<3, 1, 1>> loop,
Tyler Chatowf8f03112017-02-05 14:31:34 -0800132 const ::frc971::constants::PotAndIndexPulseZeroingConstants &estimator,
Austin Schuh473a5652017-02-05 01:30:42 -0800133 const ::frc971::constants::Range &range, double default_angular_velocity,
134 double default_angular_acceleration);
135
136 // Updates our estimator with the latest position.
137 void Correct(::frc971::PotAndIndexPosition position);
138 // Runs the controller and profile generator for a cycle.
139 void Update(bool disabled);
140
141 // Forces the current goal to the provided goal, bypassing the profiler.
142 void ForceGoal(double goal);
143 // Sets the unprofiled goal. The profiler will generate a profile to go to
144 // this goal.
145 void set_unprofiled_goal(double unprofiled_goal);
146 // Limits our profiles to a max velocity and acceleration for proper motion.
147 void AdjustProfile(double max_angular_velocity,
148 double max_angular_acceleration);
149
150 // Returns true if we have exceeded any hard limits.
151 bool CheckHardLimits();
152
153 // Returns the requested intake voltage.
154 double intake_voltage() const { return loop_->U(0, 0); }
155
156 // Returns the current position.
157 double angle() const { return Y_(0, 0); }
158
159 // For testing:
160 // Triggers an estimator error.
161 void TriggerEstimatorError() { estimators_[0].TriggerError(); }
162
163 private:
164 // Limits the provided goal to the soft limits. Prints "name" when it fails
165 // to aid debugging.
166 void CapGoal(const char *name, Eigen::Matrix<double, 3, 1> *goal);
167
168 void UpdateOffset(double offset);
169
170 aos::util::TrapezoidProfile profile_;
171
172 // Current measurement.
173 Eigen::Matrix<double, 1, 1> Y_;
174 // Current offset. Y_ = offset_ + raw_sensor;
175 Eigen::Matrix<double, 1, 1> offset_;
176
177 const ::frc971::constants::Range range_;
178
179 const double default_velocity_;
180 const double default_acceleration_;
181};
182
183} // namespace control_loops
184} // namespace frc971
185
186#endif // FRC971_CONTROL_LOOPS_PROFILED_SUBSYSTEM_H_