blob: 135b089edc878579008bfbc3bba1106e5b9ce71d [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
Stephan Pleinesf63bde82024-01-13 15:59:33 -08007namespace y2017::control_loops::superstructure::shooter {
Tyler Chatow2737d2a2017-02-08 21:20:51 -08008
9namespace chrono = ::std::chrono;
10using ::aos::monotonic_clock;
11
12namespace {
13constexpr double kTolerance = 10.0;
14} // namespace
15
16// TODO(austin): Pseudo current limit?
17
18ShooterController::ShooterController()
Austin Schuh20388b62017-11-23 22:40:46 -080019 : loop_(new StateFeedbackLoop<4, 1, 1, double,
20 StateFeedbackHybridPlant<4, 1, 1>,
Austin Schuhc66b6fc2017-03-25 19:56:59 -070021 HybridKalman<4, 1, 1>>(
Tyler Chatow2737d2a2017-02-08 21:20:51 -080022 superstructure::shooter::MakeIntegralShooterLoop())) {
23 history_.fill(0);
24 Y_.setZero();
25}
26
27void ShooterController::set_goal(double angular_velocity_goal) {
Austin Schuhc66b6fc2017-03-25 19:56:59 -070028 loop_->mutable_next_R() << 0.0, angular_velocity_goal, angular_velocity_goal,
29 0.0;
Tyler Chatow2737d2a2017-02-08 21:20:51 -080030}
31
32void ShooterController::set_position(double current_position) {
33 // Update position in the model.
34 Y_ << current_position;
35
36 // Add the position to the history.
37 history_[history_position_] = current_position;
38 history_position_ = (history_position_ + 1) % kHistoryLength;
39
Austin Schuh932a5ce2017-03-05 01:04:18 -080040 dt_position_ = current_position - last_position_;
Tyler Chatow2737d2a2017-02-08 21:20:51 -080041 last_position_ = current_position;
42}
43
44double ShooterController::voltage() const { return loop_->U(0, 0); }
45
46void ShooterController::Reset() { reset_ = true; }
47
Austin Schuh932a5ce2017-03-05 01:04:18 -080048void ShooterController::Update(bool disabled, chrono::nanoseconds dt) {
Tyler Chatow2737d2a2017-02-08 21:20:51 -080049 loop_->mutable_R() = loop_->next_R();
Austin Schuhc66b6fc2017-03-25 19:56:59 -070050 if (::std::abs(loop_->R(2, 0)) < 1.0) {
Tyler Chatow2737d2a2017-02-08 21:20:51 -080051 // Kill power at low angular velocities.
52 disabled = true;
53 }
54
55 loop_->Correct(Y_);
56
57 // Compute the oldest point in the history.
58 const int oldest_history_position =
59 ((history_position_ == 0) ? kHistoryLength : history_position_) - 1;
60
61 // Compute the distance moved over that time period.
62 average_angular_velocity_ =
63 (history_[oldest_history_position] - history_[history_position_]) /
Austin Schuh85387042017-09-13 23:59:21 -070064 (0.00505 * static_cast<double>(kHistoryLength - 1));
Tyler Chatow2737d2a2017-02-08 21:20:51 -080065
66 // Ready if average angular velocity is close to the goal.
Austin Schuhc66b6fc2017-03-25 19:56:59 -070067 error_ = average_angular_velocity_ - loop_->next_R(2, 0);
Tyler Chatow2737d2a2017-02-08 21:20:51 -080068
Austin Schuhc66b6fc2017-03-25 19:56:59 -070069 ready_ = std::abs(error_) < kTolerance && loop_->next_R(2, 0) > 1.0;
Tyler Chatow2737d2a2017-02-08 21:20:51 -080070
Austin Schuheb5c22e2017-04-09 18:30:28 -070071 // If we are no longer ready, but were, and are spinning, then we shot a ball.
72 // Reset the KF.
Austin Schuhc66b6fc2017-03-25 19:56:59 -070073 if (last_ready_ && !ready_ && loop_->next_R(2, 0) > 1.0 && error_ < 0.0) {
Tyler Chatow2737d2a2017-02-08 21:20:51 -080074 needs_reset_ = true;
Austin Schuhc66b6fc2017-03-25 19:56:59 -070075 min_velocity_ = velocity();
Tyler Chatow2737d2a2017-02-08 21:20:51 -080076 }
77 if (needs_reset_) {
Austin Schuhc66b6fc2017-03-25 19:56:59 -070078 min_velocity_ = ::std::min(min_velocity_, velocity());
79 if (velocity() > min_velocity_ + 5.0) {
Tyler Chatow2737d2a2017-02-08 21:20:51 -080080 reset_ = true;
81 needs_reset_ = false;
82 }
83 }
84 if (reset_) {
Austin Schuheb5c22e2017-04-09 18:30:28 -070085 // TODO(austin): I'd rather not be incrementing X_hat each time. Sort out
86 // something better.
Austin Schuh43603512017-04-16 19:11:37 -070087 loop_->mutable_X_hat(3, 0) += 1.0;
Tyler Chatow2737d2a2017-02-08 21:20:51 -080088 reset_ = false;
89 }
90 last_ready_ = ready_;
91
92 X_hat_current_ = loop_->X_hat();
93 position_error_ = X_hat_current_(0, 0) - Y_(0, 0);
James Kuszmaul651fc3f2019-05-15 21:14:25 -070094 dt_velocity_ = dt_position_ / ::aos::time::DurationInSeconds(dt);
Austin Schuhd6e9fb42017-04-09 17:56:06 -070095 fixed_dt_velocity_ = dt_position_ / 0.00505;
Tyler Chatow2737d2a2017-02-08 21:20:51 -080096
Austin Schuh932a5ce2017-03-05 01:04:18 -080097 loop_->Update(disabled, dt);
Tyler Chatow2737d2a2017-02-08 21:20:51 -080098}
99
Alex Perrycb7da4b2019-08-28 19:35:56 -0700100flatbuffers::Offset<ShooterStatus> ShooterController::BuildStatus(
101 flatbuffers::FlatBufferBuilder *fbb) {
102 ShooterStatus::Builder status_builder(*fbb);
103 status_builder.add_avg_angular_velocity(average_angular_velocity_);
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800104
Alex Perrycb7da4b2019-08-28 19:35:56 -0700105 status_builder.add_filtered_velocity(X_hat_current_(1, 0));
106 status_builder.add_angular_velocity(X_hat_current_(2, 0));
107 status_builder.add_ready(ready_);
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800108
Alex Perrycb7da4b2019-08-28 19:35:56 -0700109 status_builder.add_voltage_error(X_hat_current_(3, 0));
110 status_builder.add_position_error(position_error_);
111 status_builder.add_instantaneous_velocity(dt_velocity_);
112 status_builder.add_fixed_instantaneous_velocity(fixed_dt_velocity_);
113
114 return status_builder.Finish();
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800115}
116
117void Shooter::Reset() { wheel_.Reset(); }
118
Alex Perrycb7da4b2019-08-28 19:35:56 -0700119flatbuffers::Offset<ShooterStatus> Shooter::Iterate(
120 const ShooterGoalT *goal, const double position,
121 ::aos::monotonic_clock::time_point position_time, double *output,
122 flatbuffers::FlatBufferBuilder *fbb) {
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800123 if (goal) {
124 // Update position/goal for our wheel.
125 wheel_.set_goal(goal->angular_velocity);
126 }
127
Alex Perrycb7da4b2019-08-28 19:35:56 -0700128 wheel_.set_position(position);
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800129
James Kuszmaul61750662021-06-21 21:32:33 -0700130 chrono::nanoseconds dt = ::frc971::controls::kLoopFrequency;
Austin Schuh932a5ce2017-03-05 01:04:18 -0800131 if (last_time_ != ::aos::monotonic_clock::min_time) {
132 dt = position_time - last_time_;
133 }
134 last_time_ = position_time;
135
136 wheel_.Update(output == nullptr, dt);
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800137
Alex Perrycb7da4b2019-08-28 19:35:56 -0700138 flatbuffers::Offset<ShooterStatus> status_offset = wheel_.BuildStatus(fbb);
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800139
Alex Perrycb7da4b2019-08-28 19:35:56 -0700140 if (last_ready_ && !wheel_.ready()) {
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800141 min_ = wheel_.dt_velocity();
Alex Perrycb7da4b2019-08-28 19:35:56 -0700142 } else if (!wheel_.ready()) {
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800143 min_ = ::std::min(min_, wheel_.dt_velocity());
Alex Perrycb7da4b2019-08-28 19:35:56 -0700144 } else if (!last_ready_ && wheel_.ready()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700145 AOS_LOG(INFO, "Shot min was [%f]\n", min_);
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800146 }
147
148 if (output) {
149 *output = wheel_.voltage();
150 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700151 last_ready_ = wheel_.ready();
152
153 return status_offset;
Tyler Chatow2737d2a2017-02-08 21:20:51 -0800154}
155
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800156} // namespace y2017::control_loops::superstructure::shooter