blob: 19bbef14dfd85a114ef11be571504b78f4481340 [file] [log] [blame]
Comran Morshed5323ecb2015-12-26 20:50:55 +00001#include "frc971/control_loops/drivetrain/ssdrivetrain.h"
Austin Schuh64ebab22015-11-26 13:28:30 -08002
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"
Comran Morshed5323ecb2015-12-26 20:50:55 +00009#include "frc971/control_loops/drivetrain/drivetrain.q.h"
10#include "frc971/control_loops/drivetrain/drivetrain_config.h"
Austin Schuh64ebab22015-11-26 13:28:30 -080011
Comran Morshed5323ecb2015-12-26 20:50:55 +000012namespace frc971 {
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)),
Brian Silverman4e1b0662016-01-31 18:03:19 -050021 U_poly_((Eigen::Matrix<double, 4, 2>() << 1, 0, -1, 0, 0, 1, 0, -1)
Austin Schuh64ebab22015-11-26 13:28:30 -080022 .finished(),
23 (Eigen::Matrix<double, 4, 1>() << 12.0, 12.0, 12.0, 12.0)
24 .finished()) {
25 ::aos::controls::HPolytope<0>::Init();
Brian Silverman4e1b0662016-01-31 18:03:19 -050026 T_ << 1, 1, 1, -1;
27 T_inverse_ = T_.inverse();
Austin Schuh64ebab22015-11-26 13:28:30 -080028}
29
Brian Silverman4e1b0662016-01-31 18:03:19 -050030// This intentionally runs the U-capping code even when it's unnecessary to help
31// make it more deterministic. Only running it when one or both sides want
32// out-of-range voltages could lead to things like running out of CPU under
33// certain situations, which would be bad.
Austin Schuh64ebab22015-11-26 13:28:30 -080034void DrivetrainMotorsSS::LimitedDrivetrainLoop::CapU() {
Brian Silverman4e1b0662016-01-31 18:03:19 -050035 output_was_capped_ = ::std::abs(U(0, 0)) > 12.0 || ::std::abs(U(1, 0)) > 12.0;
36
Austin Schuh64ebab22015-11-26 13:28:30 -080037 const Eigen::Matrix<double, 4, 1> error = R() - X_hat();
38
Brian Silverman4e1b0662016-01-31 18:03:19 -050039 LOG_MATRIX(DEBUG, "U at start", U());
40 LOG_MATRIX(DEBUG, "R at start", R());
41 LOG_MATRIX(DEBUG, "Xhat at start", X_hat());
Austin Schuh64ebab22015-11-26 13:28:30 -080042
Brian Silverman4e1b0662016-01-31 18:03:19 -050043 Eigen::Matrix<double, 2, 2> position_K;
44 position_K << K(0, 0), K(0, 2), K(1, 0), K(1, 2);
45 Eigen::Matrix<double, 2, 2> velocity_K;
46 velocity_K << K(0, 1), K(0, 3), K(1, 1), K(1, 3);
Austin Schuh64ebab22015-11-26 13:28:30 -080047
Brian Silverman4e1b0662016-01-31 18:03:19 -050048 Eigen::Matrix<double, 2, 1> position_error;
49 position_error << error(0, 0), error(2, 0);
50 // drive_error = [total_distance_error, left_error - right_error]
51 const auto drive_error = T_inverse_ * position_error;
52 Eigen::Matrix<double, 2, 1> velocity_error;
53 velocity_error << error(1, 0), error(3, 0);
54 LOG_MATRIX(DEBUG, "error", error);
Austin Schuh64ebab22015-11-26 13:28:30 -080055
Brian Silverman4e1b0662016-01-31 18:03:19 -050056 const ::aos::controls::HPolytope<2> pos_poly(U_poly_, position_K * T_,
57 -velocity_K * velocity_error);
Austin Schuh64ebab22015-11-26 13:28:30 -080058
Brian Silverman4e1b0662016-01-31 18:03:19 -050059 Eigen::Matrix<double, 2, 1> adjusted_pos_error;
60 {
61 const auto &P = drive_error;
Austin Schuh64ebab22015-11-26 13:28:30 -080062
Brian Silverman4e1b0662016-01-31 18:03:19 -050063 Eigen::Matrix<double, 1, 2> L45;
64 L45 << ::aos::sign(P(1, 0)), -::aos::sign(P(0, 0));
65 const double w45 = 0;
Austin Schuh64ebab22015-11-26 13:28:30 -080066
Brian Silverman4e1b0662016-01-31 18:03:19 -050067 Eigen::Matrix<double, 1, 2> LH;
68 if (::std::abs(P(0, 0)) > ::std::abs(P(1, 0))) {
69 LH << 0, 1;
70 } else {
71 LH << 1, 0;
72 }
73 const double wh = LH.dot(P);
Austin Schuh64ebab22015-11-26 13:28:30 -080074
Brian Silverman4e1b0662016-01-31 18:03:19 -050075 Eigen::Matrix<double, 2, 2> standard;
76 standard << L45, LH;
77 Eigen::Matrix<double, 2, 1> W;
78 W << w45, wh;
79 const Eigen::Matrix<double, 2, 1> intersection = standard.inverse() * W;
Austin Schuh64ebab22015-11-26 13:28:30 -080080
Brian Silverman4e1b0662016-01-31 18:03:19 -050081 bool is_inside_h, is_inside_45;
82 const auto adjusted_pos_error_h =
83 DoCoerceGoal(pos_poly, LH, wh, drive_error, &is_inside_h);
84 const auto adjusted_pos_error_45 =
85 DoCoerceGoal(pos_poly, L45, w45, intersection, &is_inside_45);
86 if (pos_poly.IsInside(intersection)) {
87 adjusted_pos_error = adjusted_pos_error_h;
88 } else {
89 if (is_inside_h) {
90 if (adjusted_pos_error_h.norm() > adjusted_pos_error_45.norm() ||
91 adjusted_pos_error_45.norm() > intersection.norm()) {
92 adjusted_pos_error = adjusted_pos_error_h;
Austin Schuh64ebab22015-11-26 13:28:30 -080093 } else {
94 adjusted_pos_error = adjusted_pos_error_45;
95 }
Brian Silverman4e1b0662016-01-31 18:03:19 -050096 } else {
97 adjusted_pos_error = adjusted_pos_error_45;
Austin Schuh64ebab22015-11-26 13:28:30 -080098 }
99 }
Brian Silverman4e1b0662016-01-31 18:03:19 -0500100 }
Austin Schuh64ebab22015-11-26 13:28:30 -0800101
Brian Silverman4e1b0662016-01-31 18:03:19 -0500102 mutable_U() =
103 velocity_K * velocity_error + position_K * T_ * adjusted_pos_error;
104 LOG_MATRIX(DEBUG, "U is now", U());
105
106 if (!output_was_capped_) {
107 if ((U() - U_uncapped()).norm() > 0.0001) {
108 LOG(FATAL, "U unnecessarily capped\n");
109 }
Austin Schuh64ebab22015-11-26 13:28:30 -0800110 }
111}
112
Comran Morshed5323ecb2015-12-26 20:50:55 +0000113DrivetrainMotorsSS::DrivetrainMotorsSS(const DrivetrainConfig &dt_config)
114 : loop_(
115 new LimitedDrivetrainLoop(dt_config.make_drivetrain_loop())),
Austin Schuh64ebab22015-11-26 13:28:30 -0800116 filtered_offset_(0.0),
117 gyro_(0.0),
118 left_goal_(0.0),
119 right_goal_(0.0),
120 raw_left_(0.0),
Comran Morshed5323ecb2015-12-26 20:50:55 +0000121 raw_right_(0.0),
122 dt_config_(dt_config) {
Austin Schuh64ebab22015-11-26 13:28:30 -0800123 // High gear on both.
124 loop_->set_controller_index(3);
125}
126
127void DrivetrainMotorsSS::SetGoal(double left, double left_velocity,
128 double right, double right_velocity) {
129 left_goal_ = left;
130 right_goal_ = right;
131 loop_->mutable_R() << left, left_velocity, right, right_velocity;
132}
133void DrivetrainMotorsSS::SetRawPosition(double left, double right) {
134 raw_right_ = right;
135 raw_left_ = left;
136 Eigen::Matrix<double, 2, 1> Y;
137 Y << left + filtered_offset_, right - filtered_offset_;
138 loop_->Correct(Y);
139}
140void DrivetrainMotorsSS::SetPosition(double left, double right, double gyro) {
141 // Decay the offset quickly because this gyro is great.
Austin Schuh3130b372016-02-17 00:34:51 -0800142 const double offset = (right - left) / 2.0 - gyro * dt_config_.robot_radius;
Austin Schuh64ebab22015-11-26 13:28:30 -0800143 filtered_offset_ = 0.25 * offset + 0.75 * filtered_offset_;
144 gyro_ = gyro;
145 SetRawPosition(left, right);
146}
147
148void DrivetrainMotorsSS::SetExternalMotors(double left_voltage,
149 double right_voltage) {
150 loop_->mutable_U() << left_voltage, right_voltage;
151}
152
153void DrivetrainMotorsSS::Update(bool stop_motors, bool enable_control_loop) {
154 if (enable_control_loop) {
155 loop_->Update(stop_motors);
156 } else {
157 if (stop_motors) {
158 loop_->mutable_U().setZero();
159 loop_->mutable_U_uncapped().setZero();
160 }
Austin Schuhc2b77742015-11-26 16:18:27 -0800161 loop_->UpdateObserver(loop_->U());
Austin Schuh64ebab22015-11-26 13:28:30 -0800162 }
163 ::Eigen::Matrix<double, 4, 1> E = loop_->R() - loop_->X_hat();
164 LOG_MATRIX(DEBUG, "E", E);
165}
166
167double DrivetrainMotorsSS::GetEstimatedRobotSpeed() const {
168 // lets just call the average of left and right velocities close enough
169 return (loop_->X_hat(1, 0) + loop_->X_hat(3, 0)) / 2;
170}
171
Austin Schuh6197a182015-11-28 16:04:40 -0800172void DrivetrainMotorsSS::SendMotors(
Comran Morshed5323ecb2015-12-26 20:50:55 +0000173 ::frc971::control_loops::DrivetrainQueue::Output *output) const {
Austin Schuh64ebab22015-11-26 13:28:30 -0800174 if (output) {
175 output->left_voltage = loop_->U(0, 0);
176 output->right_voltage = loop_->U(1, 0);
177 output->left_high = true;
178 output->right_high = true;
179 }
180}
181
Austin Schuh6197a182015-11-28 16:04:40 -0800182} // namespace drivetrain
Austin Schuh64ebab22015-11-26 13:28:30 -0800183} // namespace control_loops
Comran Morshed5323ecb2015-12-26 20:50:55 +0000184} // namespace frc971