blob: 8af4a9e063db9a696bcd831d1d02ff73e9258ec7 [file] [log] [blame]
Austin Schuh87c10632017-02-05 19:02:17 -08001#include "y2017/control_loops/superstructure/hood/hood.h"
2
3#include "y2017/constants.h"
4#include "y2017/control_loops/superstructure/hood/hood_integral_plant.h"
5
6namespace y2017 {
7namespace control_loops {
8namespace superstructure {
9namespace hood {
10
11constexpr double Hood::kZeroingVoltage;
12constexpr double Hood::kOperatingVoltage;
13
14Hood::Hood()
15 : profiled_subsystem_(
16 ::std::unique_ptr<
17 ::frc971::control_loops::SimpleCappedStateFeedbackLoop<3, 1, 1>>(
18 new ::frc971::control_loops::SimpleCappedStateFeedbackLoop<
19 3, 1, 1>(MakeIntegralHoodLoop())),
20 constants::GetValues().hood.zeroing, constants::Values::kHoodRange,
21 0.5, 10.0) {}
22
23void Hood::Reset() {
24 state_ = State::UNINITIALIZED;
25 profiled_subsystem_.Reset();
26}
27
28void Hood::Iterate(const control_loops::HoodGoal *unsafe_goal,
29 const ::frc971::PotAndIndexPosition *position,
30 double *output,
31 ::frc971::control_loops::ProfiledJointStatus *status) {
32 bool disable = output == nullptr;
33 profiled_subsystem_.Correct(*position);
34
35 switch (state_) {
36 case State::UNINITIALIZED:
37 // Wait in the uninitialized state until the hood is initialized.
38 LOG(DEBUG, "Uninitialized, waiting for hood\n");
39 if (profiled_subsystem_.initialized()) {
40 state_ = State::DISABLED_INITIALIZED;
41 }
42 disable = true;
43 break;
44
45 case State::DISABLED_INITIALIZED:
46 // Wait here until we are either fully zeroed while disabled, or we become
47 // enabled.
48 if (disable) {
49 if (profiled_subsystem_.zeroed()) {
50 state_ = State::RUNNING;
51 }
52 } else {
53 state_ = State::ZEROING;
54 }
55
56 // Set the goals to where we are now so when we start back up, we don't
57 // jump.
58 profiled_subsystem_.ForceGoal(profiled_subsystem_.position());
59 // Set up the profile to be the zeroing profile.
60 profiled_subsystem_.AdjustProfile(0.10, 1);
61
62 // We are not ready to start doing anything yet.
63 disable = true;
64 break;
65
66 case State::ZEROING:
67 if (profiled_subsystem_.zeroed()) {
68 // Move the goal to the current goal so we stop moving.
69 profiled_subsystem_.set_unprofiled_goal(profiled_subsystem_.goal(0, 0));
70 state_ = State::RUNNING;
71 } else if (disable) {
72 state_ = State::DISABLED_INITIALIZED;
73 } else {
74 // Seek between the two soft limits.
75 if (profiled_subsystem_.position() >
76 (profiled_subsystem_.range().lower +
77 profiled_subsystem_.range().upper) /
78 2.0) {
79 // We are above the middle.
80 if (profiled_subsystem_.goal(1, 0) > 0) {
81 // And moving up. Keep going to the upper soft limit until we
82 // arrive.
83 profiled_subsystem_.set_unprofiled_goal(
84 profiled_subsystem_.range().upper);
85 } else {
86 // And no longer moving. Go down to the lower soft limit.
87 profiled_subsystem_.set_unprofiled_goal(
88 profiled_subsystem_.range().lower);
89 }
90 } else {
91 // We are below the middle.
92 if (profiled_subsystem_.goal(1, 0) < 0) {
93 // And moving down. Keep going to the lower soft limit until we
94 // arrive.
95 profiled_subsystem_.set_unprofiled_goal(
96 profiled_subsystem_.range().lower);
97 } else {
98 // And no longer moving. Go up to the upper soft limit.
99 profiled_subsystem_.set_unprofiled_goal(
100 profiled_subsystem_.range().upper);
101 }
102 }
103 }
104 break;
105
106 case State::RUNNING: {
107 if (disable) {
108 // Reset the profile to the current position so it starts from here when
109 // we get re-enabled.
110 profiled_subsystem_.ForceGoal(profiled_subsystem_.position());
111 }
112
113 // If we have a goal, go to it. Otherwise stay where we are.
114 if (unsafe_goal) {
115 profiled_subsystem_.AdjustProfile(unsafe_goal->profile_params);
116 profiled_subsystem_.set_unprofiled_goal(unsafe_goal->angle);
117 }
118
119 // ESTOP if we hit the hard limits.
120 if (profiled_subsystem_.CheckHardLimits()) {
121 state_ = State::ESTOP;
122 }
123 } break;
124
125 case State::ESTOP:
126 LOG(ERROR, "Estop\n");
127 disable = true;
128 break;
129 }
130
131 // Set the voltage limits.
132 const double max_voltage =
133 (state_ == State::RUNNING) ? kOperatingVoltage : kZeroingVoltage;
134
135 profiled_subsystem_.set_max_voltage({{max_voltage}});
136
137 // Calculate the loops for a cycle.
138 profiled_subsystem_.Update(disable);
139
140 // Write out all the voltages.
141 if (output) {
142 *output = profiled_subsystem_.voltage();
143 }
144
145 // Save debug/internal state.
146 // TODO(austin): Save more.
147 status->zeroed = profiled_subsystem_.zeroed();
148
149 profiled_subsystem_.PopulateStatus(status);
150 status->estopped = (state_ == State::ESTOP);
151 status->state = static_cast<int32_t>(state_);
152}
153
154} // namespace hood
155} // namespace superstructure
156} // namespace control_loops
157} // namespace y2017