blob: 0448e09d8b06826929202e240b00b20543be38ae [file] [log] [blame]
Brian Silvermanb691f5e2015-08-02 11:37:55 -07001#ifndef Y2015_CONTROL_LOOPS_FRIDGE_H_
2#define Y2015_CONTROL_LOOPS_FRIDGE_H_
Ben Fredrickson6b5ba792015-01-25 17:14:40 -08003
4#include <memory>
5
6#include "aos/common/controls/control_loop.h"
Philipp Schrader3e281412015-03-01 23:48:23 +00007#include "aos/common/util/trapezoid_profile.h"
Ben Fredrickson6b5ba792015-01-25 17:14:40 -08008#include "frc971/control_loops/state_feedback_loop.h"
Brian Silvermanb691f5e2015-08-02 11:37:55 -07009#include "y2015/control_loops/fridge/fridge.q.h"
Austin Schuh703b8d42015-02-01 14:56:34 -080010#include "frc971/zeroing/zeroing.h"
Brian Silvermanb691f5e2015-08-02 11:37:55 -070011#include "y2015/util/kinematics.h"
Ben Fredrickson6b5ba792015-01-25 17:14:40 -080012
13namespace frc971 {
14namespace control_loops {
Austin Schuhdbd6bfa2015-02-14 21:25:16 -080015namespace testing {
16class FridgeTest_DisabledGoalTest_Test;
17class FridgeTest_ArmGoalPositiveWindupTest_Test;
18class FridgeTest_ElevatorGoalPositiveWindupTest_Test;
19class FridgeTest_ArmGoalNegativeWindupTest_Test;
20class FridgeTest_ElevatorGoalNegativeWindupTest_Test;
Daniel Pettie1bb13e2015-02-17 13:59:15 -080021class FridgeTest_SafeArmZeroing_Test;
Austin Schuh8de10c72015-02-27 23:33:40 -080022} // namespace testing
Ben Fredrickson6b5ba792015-01-25 17:14:40 -080023
Austin Schuh8de10c72015-02-27 23:33:40 -080024template<int S>
25class CappedStateFeedbackLoop : public StateFeedbackLoop<S, 2, 2> {
Austin Schuh703b8d42015-02-01 14:56:34 -080026 public:
Austin Schuh8de10c72015-02-27 23:33:40 -080027 CappedStateFeedbackLoop(StateFeedbackLoop<S, 2, 2> &&loop)
28 : StateFeedbackLoop<S, 2, 2>(::std::move(loop)), max_voltage_(12.0) {}
Austin Schuh703b8d42015-02-01 14:56:34 -080029
30 void set_max_voltage(double max_voltage) {
Austin Schuh8de10c72015-02-27 23:33:40 -080031 max_voltage_ = ::std::max(0.0, ::std::min(12.0, max_voltage));
Austin Schuh703b8d42015-02-01 14:56:34 -080032 }
33
34 void CapU() override;
35
36 // Returns the amount to change the position goals (average and difference) in
37 // order to no longer saturate the controller.
38 Eigen::Matrix<double, 2, 1> UnsaturateOutputGoalChange();
39
40 private:
41 double max_voltage_;
42};
43
Ben Fredrickson6b5ba792015-01-25 17:14:40 -080044class Fridge
Brian Silverman089f5812015-02-15 01:58:19 -050045 : public aos::controls::ControlLoop<control_loops::FridgeQueue> {
Ben Fredrickson6b5ba792015-01-25 17:14:40 -080046 public:
47 explicit Fridge(
48 control_loops::FridgeQueue *fridge_queue = &control_loops::fridge_queue);
49
Austin Schuhdbd6bfa2015-02-14 21:25:16 -080050 enum State {
51 // Waiting to receive data before doing anything.
52 UNINITIALIZED = 0,
53 // Estimating the starting location.
54 INITIALIZING = 1,
55 // Moving the elevator to find an index pulse.
56 ZEROING_ELEVATOR = 2,
57 // Moving the arm to find an index pulse.
58 ZEROING_ARM = 3,
59 // All good!
60 RUNNING = 4,
61 // Internal error caused the fridge to abort.
62 ESTOP = 5,
63 };
64
Philipp Schrader085bf012015-03-15 01:43:11 +000065 enum class ProfilingType : int32_t {
66 // Use angle/height to specify the fridge goal.
67 ANGLE_HEIGHT_PROFILING = 0,
68 // Use x/y co-ordinates to specify the fridge goal.
69 X_Y_PROFILING = 1,
70 };
71
Austin Schuhdbd6bfa2015-02-14 21:25:16 -080072 State state() const { return state_; }
73
Ben Fredrickson6b5ba792015-01-25 17:14:40 -080074 protected:
Austin Schuh703b8d42015-02-01 14:56:34 -080075 void RunIteration(const control_loops::FridgeQueue::Goal *goal,
76 const control_loops::FridgeQueue::Position *position,
77 control_loops::FridgeQueue::Output *output,
78 control_loops::FridgeQueue::Status *status) override;
Ben Fredrickson6b5ba792015-01-25 17:14:40 -080079
80 private:
Austin Schuhdbd6bfa2015-02-14 21:25:16 -080081 friend class testing::FridgeTest_DisabledGoalTest_Test;
82 friend class testing::FridgeTest_ElevatorGoalPositiveWindupTest_Test;
83 friend class testing::FridgeTest_ArmGoalPositiveWindupTest_Test;
84 friend class testing::FridgeTest_ElevatorGoalNegativeWindupTest_Test;
85 friend class testing::FridgeTest_ArmGoalNegativeWindupTest_Test;
Daniel Pettie1bb13e2015-02-17 13:59:15 -080086 friend class testing::FridgeTest_SafeArmZeroing_Test;
Austin Schuhdbd6bfa2015-02-14 21:25:16 -080087
Austin Schuh703b8d42015-02-01 14:56:34 -080088 // Sets state_ to the correct state given the current state of the zeroing
89 // estimators.
90 void UpdateZeroingState();
91
92 void SetElevatorOffset(double left_offset, double right_offset);
93 void SetArmOffset(double left_offset, double right_offset);
94
95 // Getters for the current elevator positions.
96 double left_elevator();
97 double right_elevator();
98 double elevator();
99
100 // Getters for the current arm positions.
101 double left_arm();
102 double right_arm();
103 double arm();
104
105 // Our best guess at the current position of the elevator.
106 double estimated_left_elevator();
107 double estimated_right_elevator();
108 double estimated_elevator();
109
110 // Our best guess at the current position of the arm.
111 double estimated_left_arm();
112 double estimated_right_arm();
113 double estimated_arm();
114
115 // Returns the current zeroing velocity for either subsystem.
116 // If the subsystem is too far away from the center, these will switch
117 // directions.
118 double elevator_zeroing_velocity();
119 double arm_zeroing_velocity();
120
121 // Corrects the Observer with the current position.
122 void Correct();
123
Philipp Schrader3e281412015-03-01 23:48:23 +0000124 double UseUnlessZero(double target_value, double default_value);
125
Ben Fredrickson6b5ba792015-01-25 17:14:40 -0800126 // The state feedback control loop or loops to talk to.
Austin Schuh8de10c72015-02-27 23:33:40 -0800127 ::std::unique_ptr<CappedStateFeedbackLoop<5>> arm_loop_;
128 ::std::unique_ptr<CappedStateFeedbackLoop<4>> elevator_loop_;
Austin Schuh703b8d42015-02-01 14:56:34 -0800129
130 zeroing::ZeroingEstimator left_arm_estimator_;
131 zeroing::ZeroingEstimator right_arm_estimator_;
132 zeroing::ZeroingEstimator left_elevator_estimator_;
133 zeroing::ZeroingEstimator right_elevator_estimator_;
134
135 // Offsets from the encoder position to the absolute position. Add these to
136 // the encoder position to get the absolute position.
137 double left_elevator_offset_ = 0.0;
138 double right_elevator_offset_ = 0.0;
139 double left_arm_offset_ = 0.0;
140 double right_arm_offset_ = 0.0;
141
142 // Current velocity to move at while zeroing.
143 double elevator_zeroing_velocity_ = 0.0;
144 double arm_zeroing_velocity_ = 0.0;
145
146 // The goals for the elevator and arm.
147 double elevator_goal_ = 0.0;
148 double arm_goal_ = 0.0;
149
Philipp Schrader085bf012015-03-15 01:43:11 +0000150 double arm_goal_velocity_ = 0.0;
151 double elevator_goal_velocity_ = 0.0;
152
Austin Schuh703b8d42015-02-01 14:56:34 -0800153 State state_ = UNINITIALIZED;
154 State last_state_ = UNINITIALIZED;
155
156 control_loops::FridgeQueue::Position current_position_;
Philipp Schrader3e281412015-03-01 23:48:23 +0000157
Philipp Schrader085bf012015-03-15 01:43:11 +0000158 ProfilingType last_profiling_type_;
159 aos::util::ElevatorArmKinematics kinematics_;
160
Philipp Schrader3e281412015-03-01 23:48:23 +0000161 aos::util::TrapezoidProfile arm_profile_;
162 aos::util::TrapezoidProfile elevator_profile_;
Philipp Schrader085bf012015-03-15 01:43:11 +0000163
164 aos::util::TrapezoidProfile x_profile_;
165 aos::util::TrapezoidProfile y_profile_;
Ben Fredrickson6b5ba792015-01-25 17:14:40 -0800166};
167
168} // namespace control_loops
169} // namespace frc971
170
Brian Silvermanb691f5e2015-08-02 11:37:55 -0700171#endif // Y2015_CONTROL_LOOPS_FRIDGE_H_
Ben Fredrickson6b5ba792015-01-25 17:14:40 -0800172