blob: aeac5a4e2225bf411878e458f2d749bbde776a5f [file] [log] [blame]
Comran Morshed2a97bc82016-01-16 17:27:01 +00001#include "y2016/control_loops/shooter/shooter.h"
2
Austin Schuh214e9c12016-11-25 17:26:20 -08003#include <chrono>
4
John Park33858a32018-09-28 23:05:48 -07005#include "aos/logging/logging.h"
Comran Morshed2a97bc82016-01-16 17:27:01 +00006#include "y2016/control_loops/shooter/shooter_plant.h"
7
Stephan Pleinesf63bde82024-01-13 15:59:33 -08008namespace y2016::control_loops::shooter {
Austin Schuh09c2b0b2016-02-13 15:53:16 -08009
Austin Schuh214e9c12016-11-25 17:26:20 -080010namespace chrono = ::std::chrono;
Austin Schuh94a54102016-11-26 15:14:35 -080011using ::aos::monotonic_clock;
Austin Schuh7eecd7c2016-02-28 21:59:05 -080012
Austin Schuh09c2b0b2016-02-13 15:53:16 -080013// TODO(austin): Pseudo current limit?
Comran Morshed2a97bc82016-01-16 17:27:01 +000014
Comran Morshedcde50322016-01-18 15:10:36 +000015ShooterSide::ShooterSide()
Austin Schuh09c2b0b2016-02-13 15:53:16 -080016 : loop_(new StateFeedbackLoop<3, 1, 1>(MakeIntegralShooterLoop())) {
17 history_.fill(0);
18 Y_.setZero();
Comran Morshed2a97bc82016-01-16 17:27:01 +000019}
20
Austin Schuh09c2b0b2016-02-13 15:53:16 -080021void ShooterSide::set_goal(double angular_velocity_goal) {
22 loop_->mutable_next_R() << 0.0, angular_velocity_goal, 0.0;
Comran Morshedcde50322016-01-18 15:10:36 +000023}
Comran Morshed2a97bc82016-01-16 17:27:01 +000024
Austin Schuh09c2b0b2016-02-13 15:53:16 -080025void ShooterSide::set_position(double current_position) {
Comran Morshedcde50322016-01-18 15:10:36 +000026 // Update position in the model.
Austin Schuh09c2b0b2016-02-13 15:53:16 -080027 Y_ << current_position;
Comran Morshed2a97bc82016-01-16 17:27:01 +000028
Comran Morshedcde50322016-01-18 15:10:36 +000029 // Add the position to the history.
Austin Schuh09c2b0b2016-02-13 15:53:16 -080030 history_[history_position_] = current_position;
Comran Morshedcde50322016-01-18 15:10:36 +000031 history_position_ = (history_position_ + 1) % kHistoryLength;
32}
Comran Morshed2a97bc82016-01-16 17:27:01 +000033
James Kuszmaul651fc3f2019-05-15 21:14:25 -070034double ShooterSide::voltage() const { return loop_->U(0, 0); }
Comran Morshedcde50322016-01-18 15:10:36 +000035
Austin Schuh09c2b0b2016-02-13 15:53:16 -080036void ShooterSide::Update(bool disabled) {
37 loop_->mutable_R() = loop_->next_R();
38 if (loop_->R(1, 0) < 1.0) {
39 // Kill power at low angular velocities.
40 disabled = true;
41 }
42
43 loop_->Correct(Y_);
44 loop_->Update(disabled);
Comran Morshedcde50322016-01-18 15:10:36 +000045}
46
Alex Perrycb7da4b2019-08-28 19:35:56 -070047flatbuffers::Offset<ShooterSideStatus> ShooterSide::SetStatus(
48 flatbuffers::FlatBufferBuilder *fbb) {
49 ShooterSideStatus::Builder shooter_side_status_builder(*fbb);
Austin Schuh09c2b0b2016-02-13 15:53:16 -080050 // Compute the oldest point in the history.
51 const int oldest_history_position =
52 ((history_position_ == 0) ? kHistoryLength : history_position_) - 1;
Comran Morshedcde50322016-01-18 15:10:36 +000053
Austin Schuh09c2b0b2016-02-13 15:53:16 -080054 // Compute the distance moved over that time period.
Alex Perrycb7da4b2019-08-28 19:35:56 -070055 const double avg_angular_velocity =
Austin Schuh09c2b0b2016-02-13 15:53:16 -080056 (history_[oldest_history_position] - history_[history_position_]) /
James Kuszmaul61750662021-06-21 21:32:33 -070057 (::aos::time::DurationInSeconds(::frc971::controls::kLoopFrequency) *
Austin Schuh09c2b0b2016-02-13 15:53:16 -080058 static_cast<double>(kHistoryLength - 1));
Alex Perrycb7da4b2019-08-28 19:35:56 -070059 shooter_side_status_builder.add_avg_angular_velocity(avg_angular_velocity);
Austin Schuh09c2b0b2016-02-13 15:53:16 -080060
Alex Perrycb7da4b2019-08-28 19:35:56 -070061 shooter_side_status_builder.add_angular_velocity(loop_->X_hat(1, 0));
Austin Schuh09c2b0b2016-02-13 15:53:16 -080062
63 // Ready if average angular velocity is close to the goal.
Alex Perrycb7da4b2019-08-28 19:35:56 -070064 shooter_side_status_builder.add_ready(
65 (std::abs(loop_->next_R(1, 0) - avg_angular_velocity) < kTolerance &&
66 loop_->next_R(1, 0) > 1.0));
67
68 return shooter_side_status_builder.Finish();
Austin Schuh09c2b0b2016-02-13 15:53:16 -080069}
70
Austin Schuh55a13dc2019-01-27 22:39:03 -080071Shooter::Shooter(::aos::EventLoop *event_loop, const ::std::string &name)
James Kuszmaul61750662021-06-21 21:32:33 -070072 : frc971::controls::ControlLoop<Goal, Position, Status, Output>(event_loop,
73 name),
Austin Schuhf59b8ee2016-03-19 21:31:36 -070074 shots_(0),
Austin Schuh94a54102016-11-26 15:14:35 -080075 last_pre_shot_timeout_(::aos::monotonic_clock::min_time) {}
Austin Schuh09c2b0b2016-02-13 15:53:16 -080076
Alex Perrycb7da4b2019-08-28 19:35:56 -070077void Shooter::RunIteration(const Goal *goal, const Position *position,
78 aos::Sender<Output>::Builder *output,
79 aos::Sender<Status>::Builder *status) {
Austin Schuh13d68162019-07-07 20:46:44 -070080 const ::aos::monotonic_clock::time_point monotonic_now =
81 event_loop()->monotonic_now();
Comran Morshedcde50322016-01-18 15:10:36 +000082 if (goal) {
83 // Update position/goal for our two shooter sides.
Alex Perrycb7da4b2019-08-28 19:35:56 -070084 left_.set_goal(goal->angular_velocity());
85 right_.set_goal(goal->angular_velocity());
Comran Morshedcde50322016-01-18 15:10:36 +000086 }
87
Alex Perrycb7da4b2019-08-28 19:35:56 -070088 left_.set_position(position->theta_left());
89 right_.set_position(position->theta_right());
Comran Morshedcde50322016-01-18 15:10:36 +000090
Austin Schuh09c2b0b2016-02-13 15:53:16 -080091 left_.Update(output == nullptr);
92 right_.Update(output == nullptr);
Comran Morshedcde50322016-01-18 15:10:36 +000093
Alex Perrycb7da4b2019-08-28 19:35:56 -070094 flatbuffers::Offset<ShooterSideStatus> left_status_offset =
95 left_.SetStatus(status->fbb());
96 flatbuffers::Offset<ShooterSideStatus> right_status_offset =
97 right_.SetStatus(status->fbb());
98
99 ShooterSideStatus *left_status =
100 GetMutableTemporaryPointer(*status->fbb(), left_status_offset);
101 ShooterSideStatus *right_status =
102 GetMutableTemporaryPointer(*status->fbb(), right_status_offset);
103
104 const bool ready = (left_status->ready() && right_status->ready());
105
106 Status::Builder status_builder = status->MakeBuilder<Status>();
107 status_builder.add_ready((left_status->ready() && right_status->ready()));
108 status_builder.add_left(left_status_offset);
109 status_builder.add_right(right_status_offset);
Comran Morshed2a97bc82016-01-16 17:27:01 +0000110
111 if (output) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700112 Output::Builder output_builder = output->MakeBuilder<Output>();
Comran Morshedb79c4242016-02-06 18:27:26 +0000113
Alex Perrycb7da4b2019-08-28 19:35:56 -0700114 output_builder.add_voltage_left(left_.voltage());
115 output_builder.add_voltage_right(right_.voltage());
116 // Turn the lights on if we are supposed to spin.
Comran Morshedb79c4242016-02-06 18:27:26 +0000117 if (goal) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700118 bool lights_on = false;
119 if (::std::abs(goal->angular_velocity()) > 0.0) {
120 lights_on = true;
121 if (goal->shooting_forwards()) {
122 output_builder.add_forwards_flashlight(true);
123 output_builder.add_backwards_flashlight(false);
124 } else {
125 output_builder.add_forwards_flashlight(false);
126 output_builder.add_backwards_flashlight(true);
127 }
128 }
129 if (goal->force_lights_on()) {
130 lights_on = true;
131 }
132 output_builder.add_lights_on(lights_on);
133
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800134 bool shoot = false;
135 switch (state_) {
136 case ShooterLatchState::PASS_THROUGH:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700137 if (goal->push_to_shooter()) {
138 if (::std::abs(goal->angular_velocity()) > 10) {
139 if (ready) {
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800140 state_ = ShooterLatchState::WAITING_FOR_SPINDOWN;
141 shoot = true;
142 }
143 } else {
144 shoot = true;
145 }
146 }
Austin Schuh13d68162019-07-07 20:46:44 -0700147 last_pre_shot_timeout_ = monotonic_now + chrono::seconds(1);
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800148 break;
149 case ShooterLatchState::WAITING_FOR_SPINDOWN:
150 shoot = true;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700151 if (left_.velocity() < goal->angular_velocity() * 0.9 ||
152 right_.velocity() < goal->angular_velocity() * 0.9) {
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800153 state_ = ShooterLatchState::WAITING_FOR_SPINUP;
154 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700155 if (::std::abs(goal->angular_velocity()) < 10 ||
Austin Schuh13d68162019-07-07 20:46:44 -0700156 last_pre_shot_timeout_ < monotonic_now) {
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700157 state_ = ShooterLatchState::INCREMENT_SHOT_COUNT;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800158 }
159 break;
160 case ShooterLatchState::WAITING_FOR_SPINUP:
161 shoot = true;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700162 if (left_.velocity() > goal->angular_velocity() * 0.95 &&
163 right_.velocity() > goal->angular_velocity() * 0.95) {
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700164 state_ = ShooterLatchState::INCREMENT_SHOT_COUNT;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800165 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700166 if (::std::abs(goal->angular_velocity()) < 10 ||
Austin Schuh13d68162019-07-07 20:46:44 -0700167 last_pre_shot_timeout_ < monotonic_now) {
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700168 state_ = ShooterLatchState::INCREMENT_SHOT_COUNT;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800169 }
170 break;
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700171 case ShooterLatchState::INCREMENT_SHOT_COUNT:
172 ++shots_;
173 state_ = ShooterLatchState::WAITING_FOR_SHOT_NEGEDGE;
174 break;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800175 case ShooterLatchState::WAITING_FOR_SHOT_NEGEDGE:
176 shoot = true;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700177 if (!goal->push_to_shooter()) {
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800178 state_ = ShooterLatchState::PASS_THROUGH;
179 }
180 break;
181 }
182
Alex Perrycb7da4b2019-08-28 19:35:56 -0700183 output_builder.add_clamp_open(goal->clamp_open());
184 output_builder.add_push_to_shooter(shoot);
Comran Morshedb79c4242016-02-06 18:27:26 +0000185 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700186
milind1f1dca32021-07-03 13:50:07 -0700187 output->CheckOk(output->Send(output_builder.Finish()));
Comran Morshed2a97bc82016-01-16 17:27:01 +0000188 }
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700189
Alex Perrycb7da4b2019-08-28 19:35:56 -0700190 status_builder.add_shots(shots_);
191
milind1f1dca32021-07-03 13:50:07 -0700192 (void)status->Send(status_builder.Finish());
Comran Morshed2a97bc82016-01-16 17:27:01 +0000193}
194
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800195} // namespace y2016::control_loops::shooter