blob: 3c2a962d6aeeec35d66bdd115bbca8d042bd0419 [file] [log] [blame]
Austin Schuh64ebab22015-11-26 13:28:30 -08001#include "y2014/control_loops/drivetrain/ssdrivetrain.h"
2
3#include "aos/common/controls/polytope.h"
4#include "aos/common/commonmath.h"
5#include "aos/common/logging/matrix_logging.h"
6
7#include "frc971/control_loops/state_feedback_loop.h"
8#include "frc971/control_loops/coerce_goal.h"
9#include "y2014/constants.h"
10#include "y2014/control_loops/drivetrain/drivetrain.q.h"
11
Austin Schuh6197a182015-11-28 16:04:40 -080012namespace y2014 {
Austin Schuh64ebab22015-11-26 13:28:30 -080013namespace control_loops {
Austin Schuh6197a182015-11-28 16:04:40 -080014namespace drivetrain {
15
16using ::frc971::control_loops::DoCoerceGoal;
Austin Schuh64ebab22015-11-26 13:28:30 -080017
18DrivetrainMotorsSS::LimitedDrivetrainLoop::LimitedDrivetrainLoop(
19 StateFeedbackLoop<4, 2, 2> &&loop)
20 : StateFeedbackLoop<4, 2, 2>(::std::move(loop)),
21 U_Poly_((Eigen::Matrix<double, 4, 2>() << 1, 0, -1, 0, 0, 1, 0, -1)
22 .finished(),
23 (Eigen::Matrix<double, 4, 1>() << 12.0, 12.0, 12.0, 12.0)
24 .finished()) {
25 ::aos::controls::HPolytope<0>::Init();
26 T << 1, -1, 1, 1;
27 T_inverse = T.inverse();
28}
29
30void DrivetrainMotorsSS::LimitedDrivetrainLoop::CapU() {
31 const Eigen::Matrix<double, 4, 1> error = R() - X_hat();
32
33 if (::std::abs(U(0, 0)) > 12.0 || ::std::abs(U(1, 0)) > 12.0) {
34 mutable_U() =
35 U() * 12.0 / ::std::max(::std::abs(U(0, 0)), ::std::abs(U(1, 0)));
36 LOG_MATRIX(DEBUG, "U is now", U());
37 // TODO(Austin): Figure out why the polytope stuff wasn't working and
38 // remove this hack.
39 output_was_capped_ = true;
40 return;
41
42 LOG_MATRIX(DEBUG, "U at start", U());
43 LOG_MATRIX(DEBUG, "R at start", R());
44 LOG_MATRIX(DEBUG, "Xhat at start", X_hat());
45
46 Eigen::Matrix<double, 2, 2> position_K;
47 position_K << K(0, 0), K(0, 2), K(1, 0), K(1, 2);
48 Eigen::Matrix<double, 2, 2> velocity_K;
49 velocity_K << K(0, 1), K(0, 3), K(1, 1), K(1, 3);
50
51 Eigen::Matrix<double, 2, 1> position_error;
52 position_error << error(0, 0), error(2, 0);
53 const auto drive_error = T_inverse * position_error;
54 Eigen::Matrix<double, 2, 1> velocity_error;
55 velocity_error << error(1, 0), error(3, 0);
56 LOG_MATRIX(DEBUG, "error", error);
57
58 const auto &poly = U_Poly_;
59 const Eigen::Matrix<double, 4, 2> pos_poly_H = poly.H() * position_K * T;
60 const Eigen::Matrix<double, 4, 1> pos_poly_k =
61 poly.k() - poly.H() * velocity_K * velocity_error;
62 const ::aos::controls::HPolytope<2> pos_poly(pos_poly_H, pos_poly_k);
63
64 Eigen::Matrix<double, 2, 1> adjusted_pos_error;
65 {
66 const auto &P = drive_error;
67
68 Eigen::Matrix<double, 1, 2> L45;
69 L45 << ::aos::sign(P(1, 0)), -::aos::sign(P(0, 0));
70 const double w45 = 0;
71
72 Eigen::Matrix<double, 1, 2> LH;
73 if (::std::abs(P(0, 0)) > ::std::abs(P(1, 0))) {
74 LH << 0, 1;
75 } else {
76 LH << 1, 0;
77 }
78 const double wh = LH.dot(P);
79
80 Eigen::Matrix<double, 2, 2> standard;
81 standard << L45, LH;
82 Eigen::Matrix<double, 2, 1> W;
83 W << w45, wh;
84 const Eigen::Matrix<double, 2, 1> intersection = standard.inverse() * W;
85
86 bool is_inside_h;
87 const auto adjusted_pos_error_h =
88 DoCoerceGoal(pos_poly, LH, wh, drive_error, &is_inside_h);
89 const auto adjusted_pos_error_45 =
90 DoCoerceGoal(pos_poly, L45, w45, intersection, nullptr);
91 if (pos_poly.IsInside(intersection)) {
92 adjusted_pos_error = adjusted_pos_error_h;
93 } else {
94 if (is_inside_h) {
95 if (adjusted_pos_error_h.norm() > adjusted_pos_error_45.norm()) {
96 adjusted_pos_error = adjusted_pos_error_h;
97 } else {
98 adjusted_pos_error = adjusted_pos_error_45;
99 }
100 } else {
101 adjusted_pos_error = adjusted_pos_error_45;
102 }
103 }
104 }
105
106 LOG_MATRIX(DEBUG, "adjusted_pos_error", adjusted_pos_error);
107 mutable_U() =
108 velocity_K * velocity_error + position_K * T * adjusted_pos_error;
109 LOG_MATRIX(DEBUG, "U is now", U());
110 } else {
111 output_was_capped_ = false;
112 }
113}
114
115DrivetrainMotorsSS::DrivetrainMotorsSS()
116 : loop_(new LimitedDrivetrainLoop(
117 constants::GetValues().make_drivetrain_loop())),
118 filtered_offset_(0.0),
119 gyro_(0.0),
120 left_goal_(0.0),
121 right_goal_(0.0),
122 raw_left_(0.0),
123 raw_right_(0.0) {
124 // High gear on both.
125 loop_->set_controller_index(3);
126}
127
128void DrivetrainMotorsSS::SetGoal(double left, double left_velocity,
129 double right, double right_velocity) {
130 left_goal_ = left;
131 right_goal_ = right;
132 loop_->mutable_R() << left, left_velocity, right, right_velocity;
133}
134void DrivetrainMotorsSS::SetRawPosition(double left, double right) {
135 raw_right_ = right;
136 raw_left_ = left;
137 Eigen::Matrix<double, 2, 1> Y;
138 Y << left + filtered_offset_, right - filtered_offset_;
139 loop_->Correct(Y);
140}
141void DrivetrainMotorsSS::SetPosition(double left, double right, double gyro) {
142 // Decay the offset quickly because this gyro is great.
143 const double offset =
144 (right - left - gyro * constants::GetValues().turn_width) / 2.0;
145 filtered_offset_ = 0.25 * offset + 0.75 * filtered_offset_;
146 gyro_ = gyro;
147 SetRawPosition(left, right);
148}
149
150void DrivetrainMotorsSS::SetExternalMotors(double left_voltage,
151 double right_voltage) {
152 loop_->mutable_U() << left_voltage, right_voltage;
153}
154
155void DrivetrainMotorsSS::Update(bool stop_motors, bool enable_control_loop) {
156 if (enable_control_loop) {
157 loop_->Update(stop_motors);
158 } else {
159 if (stop_motors) {
160 loop_->mutable_U().setZero();
161 loop_->mutable_U_uncapped().setZero();
162 }
Austin Schuhc2b77742015-11-26 16:18:27 -0800163 loop_->UpdateObserver(loop_->U());
Austin Schuh64ebab22015-11-26 13:28:30 -0800164 }
165 ::Eigen::Matrix<double, 4, 1> E = loop_->R() - loop_->X_hat();
166 LOG_MATRIX(DEBUG, "E", E);
167}
168
169double DrivetrainMotorsSS::GetEstimatedRobotSpeed() const {
170 // lets just call the average of left and right velocities close enough
171 return (loop_->X_hat(1, 0) + loop_->X_hat(3, 0)) / 2;
172}
173
Austin Schuh6197a182015-11-28 16:04:40 -0800174void DrivetrainMotorsSS::SendMotors(
175 ::frc971::control_loops::DrivetrainQueue::Output *output) const {
Austin Schuh64ebab22015-11-26 13:28:30 -0800176 if (output) {
177 output->left_voltage = loop_->U(0, 0);
178 output->right_voltage = loop_->U(1, 0);
179 output->left_high = true;
180 output->right_high = true;
181 }
182}
183
Austin Schuh6197a182015-11-28 16:04:40 -0800184} // namespace drivetrain
Austin Schuh64ebab22015-11-26 13:28:30 -0800185} // namespace control_loops
Austin Schuh6197a182015-11-28 16:04:40 -0800186} // namespace y2014