blob: 5a5d79d56c4df8410826321b42a332e3f8b9bdc5 [file] [log] [blame]
Austin Schuh473a5652017-02-05 01:30:42 -08001#include "frc971/control_loops/profiled_subsystem.h"
2
3namespace frc971 {
4namespace control_loops {
5
6namespace {
7double UseUnlessZero(double target_value, double default_value) {
8 if (target_value != 0.0) {
9 return target_value;
10 } else {
11 return default_value;
12 }
13}
14} // namespace
15
16SingleDOFProfiledSubsystem::SingleDOFProfiledSubsystem(
17 ::std::unique_ptr<SimpleCappedStateFeedbackLoop<3, 1, 1>> loop,
Tyler Chatowf8f03112017-02-05 14:31:34 -080018 const ::frc971::constants::PotAndIndexPulseZeroingConstants &
19 zeroing_constants,
Austin Schuh473a5652017-02-05 01:30:42 -080020 const ::frc971::constants::Range &range, double default_velocity,
21 double default_acceleration)
22 : ProfiledSubsystem(::std::move(loop), {{zeroing_constants}}),
23 profile_(::aos::controls::kLoopFrequency),
24 range_(range),
25 default_velocity_(default_velocity),
26 default_acceleration_(default_acceleration) {
27 Y_.setZero();
28 offset_.setZero();
29 AdjustProfile(0.0, 0.0);
30}
31
32void SingleDOFProfiledSubsystem::UpdateOffset(double offset) {
33 const double doffset = offset - offset_(0, 0);
34 LOG(INFO, "Adjusting offset from %f to %f\n", offset_(0, 0), offset);
35
36 loop_->mutable_X_hat()(0, 0) += doffset;
37 Y_(0, 0) += doffset;
38 loop_->mutable_R(0, 0) += doffset;
39
40 profile_.MoveGoal(doffset);
41 offset_(0, 0) = offset;
42
43 CapGoal("R", &loop_->mutable_R());
44}
45
46void SingleDOFProfiledSubsystem::Correct(PotAndIndexPosition position) {
47 estimators_[0].UpdateEstimate(position);
48
49 if (estimators_[0].error()) {
50 LOG(ERROR, "zeroing error with intake_estimator\n");
51 return;
52 }
53
54 if (!initialized_) {
55 if (estimators_[0].offset_ready()) {
56 UpdateOffset(estimators_[0].offset());
57 initialized_ = true;
58 }
59 }
60
61 if (!zeroed(0) && estimators_[0].zeroed()) {
62 UpdateOffset(estimators_[0].offset());
63 set_zeroed(0, true);
64 }
65
66 Y_ << position.encoder;
67 Y_ += offset_;
68 loop_->Correct(Y_);
69}
70
71void SingleDOFProfiledSubsystem::CapGoal(const char *name,
72 Eigen::Matrix<double, 3, 1> *goal) {
73 // Limit the goal to min/max allowable angles.
74 if ((*goal)(0, 0) > range_.upper) {
75 LOG(WARNING, "Intake goal %s above limit, %f > %f\n", name, (*goal)(0, 0),
76 range_.upper);
77 (*goal)(0, 0) = range_.upper;
78 }
79 if ((*goal)(0, 0) < range_.lower) {
80 LOG(WARNING, "Intake goal %s below limit, %f < %f\n", name, (*goal)(0, 0),
81 range_.lower);
82 (*goal)(0, 0) = range_.lower;
83 }
84}
85
86void SingleDOFProfiledSubsystem::ForceGoal(double goal) {
87 set_unprofiled_goal(goal);
88 loop_->mutable_R() = unprofiled_goal_;
89 loop_->mutable_next_R() = loop_->R();
90
91 profile_.MoveCurrentState(loop_->R().block<2, 1>(0, 0));
92}
93
94void SingleDOFProfiledSubsystem::set_unprofiled_goal(double unprofiled_goal) {
95 unprofiled_goal_(0, 0) = unprofiled_goal;
96 unprofiled_goal_(1, 0) = 0.0;
97 unprofiled_goal_(2, 0) = 0.0;
98 CapGoal("unprofiled R", &unprofiled_goal_);
99}
100
101void SingleDOFProfiledSubsystem::Update(bool disable) {
102 if (!disable) {
103 ::Eigen::Matrix<double, 2, 1> goal_state =
104 profile_.Update(unprofiled_goal_(0, 0), unprofiled_goal_(1, 0));
105
106 loop_->mutable_next_R(0, 0) = goal_state(0, 0);
107 loop_->mutable_next_R(1, 0) = goal_state(1, 0);
108 loop_->mutable_next_R(2, 0) = 0.0;
109 CapGoal("next R", &loop_->mutable_next_R());
110 }
111
112 loop_->Update(disable);
113
114 if (!disable && loop_->U(0, 0) != loop_->U_uncapped(0, 0)) {
115 profile_.MoveCurrentState(loop_->R().block<2, 1>(0, 0));
116 }
117}
118
119bool SingleDOFProfiledSubsystem::CheckHardLimits() {
120 // Returns whether hard limits have been exceeded.
121
122 if (angle() > range_.upper_hard || angle() < range_.lower_hard) {
123 LOG(ERROR,
124 "SingleDOFProfiledSubsystem at %f out of bounds [%f, %f], ESTOPing\n",
125 angle(), range_.lower_hard, range_.upper_hard);
126 return true;
127 }
128
129 return false;
130}
131
132void SingleDOFProfiledSubsystem::AdjustProfile(
133 double max_angular_velocity, double max_angular_acceleration) {
134 profile_.set_maximum_velocity(
135 UseUnlessZero(max_angular_velocity, default_velocity_));
136 profile_.set_maximum_acceleration(
137 UseUnlessZero(max_angular_acceleration, default_acceleration_));
138}
139
140} // namespace control_loops
141} // namespace frc971