blob: 0ea4836353ef02efa388657105f5c721d9d29638 [file] [log] [blame]
Tyler Chatow2737d2a2017-02-08 21:20:51 -08001#include "y2017/control_loops/superstructure/shooter/shooter.h"
2
3#include <chrono>
4
John Park33858a32018-09-28 23:05:48 -07005#include "aos/logging/logging.h"
Tyler Chatow2737d2a2017-02-08 21:20:51 -08006
7namespace y2017 {
8namespace control_loops {
9namespace superstructure {
10namespace shooter {
11
12namespace chrono = ::std::chrono;
13using ::aos::monotonic_clock;
14
15namespace {
16constexpr double kTolerance = 10.0;
17} // namespace
18
19// TODO(austin): Pseudo current limit?
20
21ShooterController::ShooterController()
Austin Schuh20388b62017-11-23 22:40:46 -080022 : loop_(new StateFeedbackLoop<4, 1, 1, double,
23 StateFeedbackHybridPlant<4, 1, 1>,
Austin Schuhc66b6fc2017-03-25 19:56:59 -070024 HybridKalman<4, 1, 1>>(
Tyler Chatow2737d2a2017-02-08 21:20:51 -080025 superstructure::shooter::MakeIntegralShooterLoop())) {
26 history_.fill(0);
27 Y_.setZero();
28}
29
30void ShooterController::set_goal(double angular_velocity_goal) {
Austin Schuhc66b6fc2017-03-25 19:56:59 -070031 loop_->mutable_next_R() << 0.0, angular_velocity_goal, angular_velocity_goal,
32 0.0;
Tyler Chatow2737d2a2017-02-08 21:20:51 -080033}
34
35void ShooterController::set_position(double current_position) {
36 // Update position in the model.
37 Y_ << current_position;
38
39 // Add the position to the history.
40 history_[history_position_] = current_position;
41 history_position_ = (history_position_ + 1) % kHistoryLength;
42
Austin Schuh932a5ce2017-03-05 01:04:18 -080043 dt_position_ = current_position - last_position_;
Tyler Chatow2737d2a2017-02-08 21:20:51 -080044 last_position_ = current_position;
45}
46
47double ShooterController::voltage() const { return loop_->U(0, 0); }
48
49void ShooterController::Reset() { reset_ = true; }
50
Austin Schuh932a5ce2017-03-05 01:04:18 -080051void ShooterController::Update(bool disabled, chrono::nanoseconds dt) {
Tyler Chatow2737d2a2017-02-08 21:20:51 -080052 loop_->mutable_R() = loop_->next_R();
Austin Schuhc66b6fc2017-03-25 19:56:59 -070053 if (::std::abs(loop_->R(2, 0)) < 1.0) {
Tyler Chatow2737d2a2017-02-08 21:20:51 -080054 // Kill power at low angular velocities.
55 disabled = true;
56 }
57
58 loop_->Correct(Y_);
59
60 // Compute the oldest point in the history.
61 const int oldest_history_position =
62 ((history_position_ == 0) ? kHistoryLength : history_position_) - 1;
63
64 // Compute the distance moved over that time period.
65 average_angular_velocity_ =
66 (history_[oldest_history_position] - history_[history_position_]) /
Austin Schuh85387042017-09-13 23:59:21 -070067 (0.00505 * static_cast<double>(kHistoryLength - 1));
Tyler Chatow2737d2a2017-02-08 21:20:51 -080068
69 // Ready if average angular velocity is close to the goal.
Austin Schuhc66b6fc2017-03-25 19:56:59 -070070 error_ = average_angular_velocity_ - loop_->next_R(2, 0);
Tyler Chatow2737d2a2017-02-08 21:20:51 -080071
Austin Schuhc66b6fc2017-03-25 19:56:59 -070072 ready_ = std::abs(error_) < kTolerance && loop_->next_R(2, 0) > 1.0;
Tyler Chatow2737d2a2017-02-08 21:20:51 -080073
Austin Schuheb5c22e2017-04-09 18:30:28 -070074 // If we are no longer ready, but were, and are spinning, then we shot a ball.
75 // Reset the KF.
Austin Schuhc66b6fc2017-03-25 19:56:59 -070076 if (last_ready_ && !ready_ && loop_->next_R(2, 0) > 1.0 && error_ < 0.0) {
Tyler Chatow2737d2a2017-02-08 21:20:51 -080077 needs_reset_ = true;
Austin Schuhc66b6fc2017-03-25 19:56:59 -070078 min_velocity_ = velocity();
Tyler Chatow2737d2a2017-02-08 21:20:51 -080079 }
80 if (needs_reset_) {
Austin Schuhc66b6fc2017-03-25 19:56:59 -070081 min_velocity_ = ::std::min(min_velocity_, velocity());
82 if (velocity() > min_velocity_ + 5.0) {
Tyler Chatow2737d2a2017-02-08 21:20:51 -080083 reset_ = true;
84 needs_reset_ = false;
85 }
86 }
87 if (reset_) {
Austin Schuheb5c22e2017-04-09 18:30:28 -070088 // TODO(austin): I'd rather not be incrementing X_hat each time. Sort out
89 // something better.
Austin Schuh43603512017-04-16 19:11:37 -070090 loop_->mutable_X_hat(3, 0) += 1.0;
Tyler Chatow2737d2a2017-02-08 21:20:51 -080091 reset_ = false;
92 }
93 last_ready_ = ready_;
94
95 X_hat_current_ = loop_->X_hat();
96 position_error_ = X_hat_current_(0, 0) - Y_(0, 0);
James Kuszmaul651fc3f2019-05-15 21:14:25 -070097 dt_velocity_ = dt_position_ / ::aos::time::DurationInSeconds(dt);
Austin Schuhd6e9fb42017-04-09 17:56:06 -070098 fixed_dt_velocity_ = dt_position_ / 0.00505;
Tyler Chatow2737d2a2017-02-08 21:20:51 -080099
Austin Schuh932a5ce2017-03-05 01:04:18 -0800100 loop_->Update(disabled, dt);
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800101}
102
Alex Perrycb7da4b2019-08-28 19:35:56 -0700103flatbuffers::Offset<ShooterStatus> ShooterController::BuildStatus(
104 flatbuffers::FlatBufferBuilder *fbb) {
105 ShooterStatus::Builder status_builder(*fbb);
106 status_builder.add_avg_angular_velocity(average_angular_velocity_);
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800107
Alex Perrycb7da4b2019-08-28 19:35:56 -0700108 status_builder.add_filtered_velocity(X_hat_current_(1, 0));
109 status_builder.add_angular_velocity(X_hat_current_(2, 0));
110 status_builder.add_ready(ready_);
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800111
Alex Perrycb7da4b2019-08-28 19:35:56 -0700112 status_builder.add_voltage_error(X_hat_current_(3, 0));
113 status_builder.add_position_error(position_error_);
114 status_builder.add_instantaneous_velocity(dt_velocity_);
115 status_builder.add_fixed_instantaneous_velocity(fixed_dt_velocity_);
116
117 return status_builder.Finish();
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800118}
119
120void Shooter::Reset() { wheel_.Reset(); }
121
Alex Perrycb7da4b2019-08-28 19:35:56 -0700122flatbuffers::Offset<ShooterStatus> Shooter::Iterate(
123 const ShooterGoalT *goal, const double position,
124 ::aos::monotonic_clock::time_point position_time, double *output,
125 flatbuffers::FlatBufferBuilder *fbb) {
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800126 if (goal) {
127 // Update position/goal for our wheel.
128 wheel_.set_goal(goal->angular_velocity);
129 }
130
Alex Perrycb7da4b2019-08-28 19:35:56 -0700131 wheel_.set_position(position);
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800132
Austin Schuh932a5ce2017-03-05 01:04:18 -0800133 chrono::nanoseconds dt = ::aos::controls::kLoopFrequency;
134 if (last_time_ != ::aos::monotonic_clock::min_time) {
135 dt = position_time - last_time_;
136 }
137 last_time_ = position_time;
138
139 wheel_.Update(output == nullptr, dt);
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800140
Alex Perrycb7da4b2019-08-28 19:35:56 -0700141 flatbuffers::Offset<ShooterStatus> status_offset = wheel_.BuildStatus(fbb);
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800142
Alex Perrycb7da4b2019-08-28 19:35:56 -0700143 if (last_ready_ && !wheel_.ready()) {
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800144 min_ = wheel_.dt_velocity();
Alex Perrycb7da4b2019-08-28 19:35:56 -0700145 } else if (!wheel_.ready()) {
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800146 min_ = ::std::min(min_, wheel_.dt_velocity());
Alex Perrycb7da4b2019-08-28 19:35:56 -0700147 } else if (!last_ready_ && wheel_.ready()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700148 AOS_LOG(INFO, "Shot min was [%f]\n", min_);
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800149 }
150
151 if (output) {
152 *output = wheel_.voltage();
153 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700154 last_ready_ = wheel_.ready();
155
156 return status_offset;
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800157}
158
159} // namespace shooter
160} // namespace superstructure
161} // namespace control_loops
162} // namespace y2017