blob: 102032e51dbe3015d898f06d7d36d985f99ce802 [file] [log] [blame]
James Kuszmaulcdd033e2013-03-02 15:10:43 -08001#include "frc971/control_loops/shooter.h"
2
3#include "aos/aos_core.h"
4
5#include "aos/common/control_loop/control_loops.q.h"
6#include "aos/common/logging/logging.h"
7
8#include "frc971/control_loops/shooter_motor_plant.h"
9
10namespace frc971 {
11namespace control_loops {
12
13namespace {
14// Motor controllers have a range of PWM values where they don't trigger,
15// and we use these values to avoid that.
16// TODO: find these values for the Talons.
17static const double positive_deadband_power = 0.0;
18static const double negative_deadband_power = 0.0;
19}
20
21ShooterMotor::ShooterMotor(control_loops::ShooterLoop *my_shooter)
22 : aos::control_loops::ControlLoop<control_loops::ShooterLoop>(my_shooter),
23 loop_(new StateFeedbackLoop<2, 1, 1>(MakeShooterLoop())),
24 history_position_(0),
25 position_goal_(0.0),
26 time_(0.0) {
27 memset(history, 0, sizeof(history));
28 // Creates the header for the data file. Overwrites anything already there.
29 loop_->StartDataFile("shooter.csv");
30}
31
32void ShooterMotor::RunIteration(
33 const control_loops::ShooterLoop::Goal *goal,
34 const control_loops::ShooterLoop::Position *position,
35 ::aos::control_loops::Output *output,
36 control_loops::ShooterLoop::Status *status) {
37
38 bool bad_pos = false;
39 if (position == NULL) {
40 LOG(WARNING, "no position given\n");
41 bad_pos = true;
42 }
43
44 const double velocity_goal = std::min(goal->velocity, max_speed);
45 static double last_position = 0.0;
46 double output_voltage = 0.0;
47
48 if (!bad_pos) {
49 static bool first_time = true;
50 if (first_time) {
51 position_goal_ = position->position;
52 first_time = false;
53 }
54
55 // Add position to the history.
56 history[history_position_] = position->position;
57 history_position_ = (history_position_ + 1) % kHistoryLength;
58
59 loop_->Y << position->position;
60 // Prevents the position from going out of the bounds
61 // where the control loop will run the motor at full power.
62 const double velocity_weight_scalar = 0.35;
63 const double max_reference = (loop_->plant.U_max[0] - velocity_weight_scalar *
64 (velocity_goal - loop_->X_hat[1]) * loop_->K[1])
65 / loop_->K[0] + loop_->X_hat[0];
66 const double min_reference = (loop_->plant.U_min[0] - velocity_weight_scalar *
67 (velocity_goal - loop_->X_hat[1]) * loop_->K[1])
68 / loop_->K[0] + loop_->X_hat[0];
69 position_goal_ = std::max(std::min(position_goal_, max_reference), min_reference);
70 loop_->R << position_goal_, velocity_goal;
71 position_goal_ += velocity_goal * dt;
72 }
73
74 loop_->Update(!bad_pos, bad_pos || (output == NULL));
75 // There is no need to make the motors actively assist the spin-down.
76 if (velocity_goal < 1.0) {
77 output_voltage = 0.0;
78 // Also, reset the position incrementer to avoid accumulating error.
79 position_goal_ = position->position;
80 } else {
81 output_voltage = loop_->U[0] / 12.0;
82 }
83 LOG(DEBUG,
84 "PWM: %f, raw_pos: %f rotations: %f "
85 "junk velocity: %f, xhat[0]: %f xhat[1]: %f, R[0]: %f R[1]: %f\n",
86 output_voltage, position->position,
87 position->position / (2 * M_PI),
88 (position->position - last_position) / dt,
89 loop_->X_hat[0], loop_->X_hat[1], loop_->R[0], loop_->R[1]);
90
91// aos::DriverStationDisplay::Send(2, "RPS%3.0f(%3.0f) RPM%4.0f",
92// (position->position - last_position) * 100.0, goal->goal,
93// (position->position - last_position) / (2.0 * M_PI) * 6000.0);
94
95 // Calculates the velocity over the last kHistoryLength*.001 seconds
96 // by taking the difference between the current and next history positions.
97 int old_history_position = ((history_position_ == 0) ?
98 kHistoryLength : history_position_) - 1;
99 average_velocity_ = (history[old_history_position]
100 - history[history_position_]) * 100.0 / (double)(kHistoryLength - 1);
101 status->average_velocity = average_velocity_;
102 // Determines if the velocity is close enough to the goal to be ready.
103 if (std::abs(velocity_goal - average_velocity_) < 10.0 &&
104 velocity_goal != 0.0) {
105 LOG(DEBUG, "Steady: ");
106 status->ready = true;
107 } else {
108 LOG(DEBUG, "Not ready: ");
109 status->ready = false;
110 }
111 LOG(DEBUG, "avg = %f goal = %f\n", average_velocity_, velocity_goal);
112
113 // Deal with motor controller deadbands.
114 if (output_voltage > 0) {
115 output_voltage += positive_deadband_power;
116 }
117 if (output_voltage < 0) {
118 output_voltage -= negative_deadband_power;
119 }
120
121 if (bad_pos) {
122 last_position = position->position;
123 } else {
124 // use the predicted position
125 last_position = loop_->X_hat[0];
126 }
127 if (output) {
128 output->voltage = output_voltage;
129 }
130
131 // If anything is happening, record it. Otherwise, reset the time.
132 // This should be removed once we are done with testing.
133 if (output_voltage != 0 && average_velocity_ != 0 && velocity_goal != 0) {
134 loop_->RecordDatum("shooter.csv", time_);
135 time_ += dt;
136 }
137 else {
138 time_ = 0;
139 }
140} // RunIteration
141
142} // namespace control_loops
143} // namespace frc971