blob: 45ab4eb996ab8a2f6736b139bb2725329d2e9936 [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) {
Brian Silvermanb61f34a2016-01-03 19:55:16 -080095 if (adjusted_pos_error_h.norm() > adjusted_pos_error_45.norm() ||
96 adjusted_pos_error_45.norm() > intersection.norm()) {
Austin Schuh64ebab22015-11-26 13:28:30 -080097 adjusted_pos_error = adjusted_pos_error_h;
98 } else {
99 adjusted_pos_error = adjusted_pos_error_45;
100 }
101 } else {
102 adjusted_pos_error = adjusted_pos_error_45;
103 }
104 }
105 }
106
107 LOG_MATRIX(DEBUG, "adjusted_pos_error", adjusted_pos_error);
108 mutable_U() =
109 velocity_K * velocity_error + position_K * T * adjusted_pos_error;
110 LOG_MATRIX(DEBUG, "U is now", U());
111 } else {
112 output_was_capped_ = false;
113 }
114}
115
116DrivetrainMotorsSS::DrivetrainMotorsSS()
117 : loop_(new LimitedDrivetrainLoop(
118 constants::GetValues().make_drivetrain_loop())),
119 filtered_offset_(0.0),
120 gyro_(0.0),
121 left_goal_(0.0),
122 right_goal_(0.0),
123 raw_left_(0.0),
124 raw_right_(0.0) {
125 // High gear on both.
126 loop_->set_controller_index(3);
127}
128
129void DrivetrainMotorsSS::SetGoal(double left, double left_velocity,
130 double right, double right_velocity) {
131 left_goal_ = left;
132 right_goal_ = right;
133 loop_->mutable_R() << left, left_velocity, right, right_velocity;
134}
135void DrivetrainMotorsSS::SetRawPosition(double left, double right) {
136 raw_right_ = right;
137 raw_left_ = left;
138 Eigen::Matrix<double, 2, 1> Y;
139 Y << left + filtered_offset_, right - filtered_offset_;
140 loop_->Correct(Y);
141}
142void DrivetrainMotorsSS::SetPosition(double left, double right, double gyro) {
143 // Decay the offset quickly because this gyro is great.
144 const double offset =
145 (right - left - gyro * constants::GetValues().turn_width) / 2.0;
146 filtered_offset_ = 0.25 * offset + 0.75 * filtered_offset_;
147 gyro_ = gyro;
148 SetRawPosition(left, right);
149}
150
151void DrivetrainMotorsSS::SetExternalMotors(double left_voltage,
152 double right_voltage) {
153 loop_->mutable_U() << left_voltage, right_voltage;
154}
155
156void DrivetrainMotorsSS::Update(bool stop_motors, bool enable_control_loop) {
157 if (enable_control_loop) {
158 loop_->Update(stop_motors);
159 } else {
160 if (stop_motors) {
161 loop_->mutable_U().setZero();
162 loop_->mutable_U_uncapped().setZero();
163 }
Austin Schuhc2b77742015-11-26 16:18:27 -0800164 loop_->UpdateObserver(loop_->U());
Austin Schuh64ebab22015-11-26 13:28:30 -0800165 }
166 ::Eigen::Matrix<double, 4, 1> E = loop_->R() - loop_->X_hat();
167 LOG_MATRIX(DEBUG, "E", E);
168}
169
170double DrivetrainMotorsSS::GetEstimatedRobotSpeed() const {
171 // lets just call the average of left and right velocities close enough
172 return (loop_->X_hat(1, 0) + loop_->X_hat(3, 0)) / 2;
173}
174
Austin Schuh6197a182015-11-28 16:04:40 -0800175void DrivetrainMotorsSS::SendMotors(
Brian Silvermanb601d892015-12-20 18:24:38 -0500176 ::y2014::control_loops::DrivetrainQueue::Output *output) const {
Austin Schuh64ebab22015-11-26 13:28:30 -0800177 if (output) {
178 output->left_voltage = loop_->U(0, 0);
179 output->right_voltage = loop_->U(1, 0);
180 output->left_high = true;
181 output->right_high = true;
182 }
183}
184
Austin Schuh6197a182015-11-28 16:04:40 -0800185} // namespace drivetrain
Austin Schuh64ebab22015-11-26 13:28:30 -0800186} // namespace control_loops
Austin Schuh6197a182015-11-28 16:04:40 -0800187} // namespace y2014