blob: b4c04a38aa99bd69f029359cd08ec3d0ef63309f [file] [log] [blame]
Comran Morshed5323ecb2015-12-26 20:50:55 +00001#include "frc971/control_loops/drivetrain/drivetrain.h"
Brian Silverman17f503e2015-08-02 18:17:18 -07002
3#include <stdio.h>
4#include <sched.h>
5#include <cmath>
6#include <memory>
7#include "Eigen/Dense"
8
9#include "aos/common/logging/logging.h"
Brian Silverman17f503e2015-08-02 18:17:18 -070010#include "aos/common/logging/queue_logging.h"
11#include "aos/common/logging/matrix_logging.h"
12
Comran Morshed5323ecb2015-12-26 20:50:55 +000013#include "frc971/control_loops/drivetrain/drivetrain.q.h"
14#include "frc971/control_loops/drivetrain/polydrivetrain.h"
15#include "frc971/control_loops/drivetrain/ssdrivetrain.h"
16#include "frc971/control_loops/drivetrain/drivetrain_config.h"
Brian Silverman17f503e2015-08-02 18:17:18 -070017#include "frc971/queues/gyro.q.h"
18#include "frc971/shifter_hall_effect.h"
19
Brian Silverman17f503e2015-08-02 18:17:18 -070020using frc971::sensors::gyro_reading;
21
Comran Morshed5323ecb2015-12-26 20:50:55 +000022namespace frc971 {
Brian Silverman17f503e2015-08-02 18:17:18 -070023namespace control_loops {
Austin Schuh6197a182015-11-28 16:04:40 -080024namespace drivetrain {
Brian Silverman17f503e2015-08-02 18:17:18 -070025
Austin Schuh209f1702015-11-29 17:03:00 -080026DrivetrainLoop::DrivetrainLoop(
Comran Morshed5323ecb2015-12-26 20:50:55 +000027 const DrivetrainConfig &dt_config,
28 ::frc971::control_loops::DrivetrainQueue *my_drivetrain)
29 : aos::controls::ControlLoop<::frc971::control_loops::DrivetrainQueue>(
Austin Schuh209f1702015-11-29 17:03:00 -080030 my_drivetrain),
Comran Morshed5323ecb2015-12-26 20:50:55 +000031 dt_config_(dt_config),
Austin Schuh41565602016-02-28 20:10:49 -080032 kf_(dt_config_.make_kf_drivetrain_loop()),
33 dt_openloop_(dt_config_, &kf_),
Austin Schuh093535c2016-03-05 23:21:00 -080034 dt_closedloop_(dt_config_, &kf_, &integrated_kf_heading_),
35 left_gear_(dt_config_.default_high_gear ? Gear::HIGH : Gear::LOW),
36 right_gear_(dt_config_.default_high_gear ? Gear::HIGH : Gear::LOW),
37 left_high_requested_(dt_config_.default_high_gear),
38 right_high_requested_(dt_config_.default_high_gear) {
Austin Schuh209f1702015-11-29 17:03:00 -080039 ::aos::controls::HPolytope<0>::Init();
40}
41
Austin Schuh093535c2016-03-05 23:21:00 -080042int DrivetrainLoop::ControllerIndexFromGears() {
43 if (MaybeHigh(left_gear_)) {
44 if (MaybeHigh(right_gear_)) {
45 return 3;
46 } else {
47 return 2;
48 }
49 } else {
50 if (MaybeHigh(right_gear_)) {
51 return 1;
52 } else {
53 return 0;
54 }
55 }
56}
57
58Gear ComputeGear(double shifter_position,
59 const constants::ShifterHallEffect &shifter_config,
60 bool high_requested) {
61 if (shifter_position < shifter_config.clear_low) {
62 return Gear::LOW;
63 } else if (shifter_position > shifter_config.clear_high) {
64 return Gear::HIGH;
65 } else {
66 if (high_requested) {
67 return Gear::SHIFTING_UP;
68 } else {
69 return Gear::SHIFTING_DOWN;
70 }
71 }
72}
73
Austin Schuh6197a182015-11-28 16:04:40 -080074void DrivetrainLoop::RunIteration(
Comran Morshed5323ecb2015-12-26 20:50:55 +000075 const ::frc971::control_loops::DrivetrainQueue::Goal *goal,
76 const ::frc971::control_loops::DrivetrainQueue::Position *position,
77 ::frc971::control_loops::DrivetrainQueue::Output *output,
78 ::frc971::control_loops::DrivetrainQueue::Status *status) {
Austin Schuh093535c2016-03-05 23:21:00 -080079 // TODO(austin): Put gear detection logic here.
80 switch (dt_config_.shifter_type) {
81 case ShifterType::SIMPLE_SHIFTER:
82 // Force the right controller for simple shifters since we assume that
83 // gear switching is instantaneous.
84 if (left_high_requested_) {
85 left_gear_ = Gear::HIGH;
86 } else {
87 left_gear_ = Gear::LOW;
88 }
89 if (right_high_requested_) {
90 right_gear_ = Gear::HIGH;
91 } else {
92 right_gear_ = Gear::LOW;
93 }
94 break;
95 case ShifterType::HALL_EFFECT_SHIFTER:
96 left_gear_ = ComputeGear(position->left_shifter_position,
97 dt_config_.left_drive, left_high_requested_);
98 right_gear_ = ComputeGear(position->right_shifter_position,
99 dt_config_.right_drive, right_high_requested_);
100 break;
Brian Silverman17f503e2015-08-02 18:17:18 -0700101 }
Brian Silverman17f503e2015-08-02 18:17:18 -0700102
Austin Schuh093535c2016-03-05 23:21:00 -0800103 kf_.set_controller_index(ControllerIndexFromGears());
104 {
105 GearLogging gear_logging;
106 gear_logging.left_state = static_cast<uint32_t>(left_gear_);
107 gear_logging.right_state = static_cast<uint32_t>(right_gear_);
108 gear_logging.left_loop_high = MaybeHigh(left_gear_);
109 gear_logging.right_loop_high = MaybeHigh(right_gear_);
110 gear_logging.controller_index = kf_.controller_index();
111 LOG_STRUCT(DEBUG, "state", gear_logging);
112 }
Austin Schuh6613a072016-01-06 19:54:48 -0800113
Austin Schuh093535c2016-03-05 23:21:00 -0800114 // TODO(austin): Signal the current gear to both loops.
115
Austin Schuh9ab4d9d2016-02-16 23:55:44 -0800116 if (gyro_reading.FetchLatest()) {
117 LOG_STRUCT(DEBUG, "using", *gyro_reading.get());
118 last_gyro_heading_ = gyro_reading->angle;
119 last_gyro_rate_ = gyro_reading->velocity;
Austin Schuh9ab4d9d2016-02-16 23:55:44 -0800120 }
121
Austin Schuh6613a072016-01-06 19:54:48 -0800122 {
123 Eigen::Matrix<double, 3, 1> Y;
124 Y << position->left_encoder, position->right_encoder, last_gyro_rate_;
125 kf_.Correct(Y);
Comran Morshed5323ecb2015-12-26 20:50:55 +0000126 integrated_kf_heading_ += dt_config_.dt *
127 (kf_.X_hat(3, 0) - kf_.X_hat(1, 0)) /
128 (dt_config_.robot_radius * 2.0);
Austin Schuh093535c2016-03-05 23:21:00 -0800129
130 // gyro_heading = (real_right - real_left) / width
131 // wheel_heading = (wheel_right - wheel_left) / width
132 // gyro_heading + offset = wheel_heading
133 // gyro_goal + offset = wheel_goal
134 // offset = wheel_heading - gyro_heading
135
136 // gyro_goal + wheel_heading - gyro_heading = wheel_goal
Austin Schuh6613a072016-01-06 19:54:48 -0800137 }
138
Austin Schuh093535c2016-03-05 23:21:00 -0800139 dt_openloop_.SetPosition(position, left_gear_, right_gear_);
140
Brian Silverman17f503e2015-08-02 18:17:18 -0700141 bool control_loop_driving = false;
142 if (goal) {
Brian Silverman17f503e2015-08-02 18:17:18 -0700143 control_loop_driving = goal->control_loop_driving;
Brian Silverman17f503e2015-08-02 18:17:18 -0700144
Austin Schuh093535c2016-03-05 23:21:00 -0800145 dt_closedloop_.SetGoal(*goal);
146 dt_openloop_.SetGoal(*goal);
Brian Silverman17f503e2015-08-02 18:17:18 -0700147 }
148
Austin Schuh64ebab22015-11-26 13:28:30 -0800149 dt_openloop_.Update();
Brian Silverman17f503e2015-08-02 18:17:18 -0700150
151 if (control_loop_driving) {
Austin Schuh093535c2016-03-05 23:21:00 -0800152 dt_closedloop_.Update(output != NULL);
153 dt_closedloop_.SetOutput(output);
Brian Silverman17f503e2015-08-02 18:17:18 -0700154 } else {
Austin Schuh093535c2016-03-05 23:21:00 -0800155 dt_openloop_.SetOutput(output);
156 // TODO(austin): Set profile to current spot.
157 dt_closedloop_.Update(false);
Brian Silverman17f503e2015-08-02 18:17:18 -0700158 }
159
Austin Schuh093535c2016-03-05 23:21:00 -0800160 // The output should now contain the shift request.
161
Brian Silverman17f503e2015-08-02 18:17:18 -0700162 // set the output status of the control loop state
163 if (status) {
Austin Schuh093535c2016-03-05 23:21:00 -0800164 status->robot_speed = (kf_.X_hat(1, 0) + kf_.X_hat(3, 0)) / 2.0;
Brian Silverman17f503e2015-08-02 18:17:18 -0700165
Austin Schuh093535c2016-03-05 23:21:00 -0800166 Eigen::Matrix<double, 2, 1> linear =
167 dt_closedloop_.LeftRightToLinear(kf_.X_hat());
168 Eigen::Matrix<double, 2, 1> angular =
169 dt_closedloop_.LeftRightToAngular(kf_.X_hat());
170
171 angular(0, 0) = integrated_kf_heading_;
172
173 Eigen::Matrix<double, 4, 1> gyro_left_right =
174 dt_closedloop_.AngularLinearToLeftRight(linear, angular);
175
176 status->estimated_left_position = gyro_left_right(0, 0);
177 status->estimated_right_position = gyro_left_right(2, 0);
178
179 status->estimated_left_velocity = gyro_left_right(1, 0);
180 status->estimated_right_velocity = gyro_left_right(3, 0);
181 status->output_was_capped = dt_closedloop_.output_was_capped();
182 status->uncapped_left_voltage = kf_.U_uncapped(0, 0);
183 status->uncapped_right_voltage = kf_.U_uncapped(1, 0);
184
185 status->left_voltage_error = kf_.X_hat(4, 0);
186 status->right_voltage_error = kf_.X_hat(5, 0);
187 status->estimated_angular_velocity_error = kf_.X_hat(6, 0);
188 status->estimated_heading = integrated_kf_heading_;
Austin Schuh41565602016-02-28 20:10:49 -0800189
190 dt_openloop_.PopulateStatus(status);
Austin Schuh093535c2016-03-05 23:21:00 -0800191 dt_closedloop_.PopulateStatus(status);
Brian Silverman17f503e2015-08-02 18:17:18 -0700192 }
Austin Schuh209f1702015-11-29 17:03:00 -0800193
Austin Schuh209f1702015-11-29 17:03:00 -0800194 double left_voltage = 0.0;
195 double right_voltage = 0.0;
196 if (output) {
197 left_voltage = output->left_voltage;
198 right_voltage = output->right_voltage;
Austin Schuh093535c2016-03-05 23:21:00 -0800199 left_high_requested_ = output->left_high;
200 right_high_requested_ = output->right_high;
Austin Schuh209f1702015-11-29 17:03:00 -0800201 }
202
203 const double scalar = ::aos::robot_state->voltage_battery / 12.0;
204
205 left_voltage *= scalar;
206 right_voltage *= scalar;
207
Austin Schuh209f1702015-11-29 17:03:00 -0800208 // To validate, look at the following:
209
210 // Observed - dx/dt velocity for left, right.
211
212 // Angular velocity error compared to the gyro
213 // Gyro heading vs left-right
214 // Voltage error.
215
216 Eigen::Matrix<double, 2, 1> U;
217 U << last_left_voltage_, last_right_voltage_;
218 last_left_voltage_ = left_voltage;
219 last_right_voltage_ = right_voltage;
220
221 kf_.UpdateObserver(U);
Brian Silverman17f503e2015-08-02 18:17:18 -0700222}
223
Adam Snaiderbc918b62016-02-27 21:03:39 -0800224void DrivetrainLoop::Zero(
225 ::frc971::control_loops::DrivetrainQueue::Output *output) {
226 output->left_voltage = 0;
227 output->right_voltage = 0;
228 output->left_high = dt_config_.default_high_gear;
229 output->right_high = dt_config_.default_high_gear;
230}
231
Austin Schuh6197a182015-11-28 16:04:40 -0800232} // namespace drivetrain
Brian Silverman17f503e2015-08-02 18:17:18 -0700233} // namespace control_loops
Comran Morshed5323ecb2015-12-26 20:50:55 +0000234} // namespace frc971