blob: 5156a618fdeb624679f4e0f154a2f2a08cf7c5db [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
8namespace y2016 {
9namespace control_loops {
Austin Schuh09c2b0b2016-02-13 15:53:16 -080010namespace shooter {
11
Austin Schuh214e9c12016-11-25 17:26:20 -080012namespace chrono = ::std::chrono;
Austin Schuh94a54102016-11-26 15:14:35 -080013using ::aos::monotonic_clock;
Austin Schuh7eecd7c2016-02-28 21:59:05 -080014
Austin Schuh09c2b0b2016-02-13 15:53:16 -080015// TODO(austin): Pseudo current limit?
Comran Morshed2a97bc82016-01-16 17:27:01 +000016
Comran Morshedcde50322016-01-18 15:10:36 +000017ShooterSide::ShooterSide()
Austin Schuh09c2b0b2016-02-13 15:53:16 -080018 : loop_(new StateFeedbackLoop<3, 1, 1>(MakeIntegralShooterLoop())) {
19 history_.fill(0);
20 Y_.setZero();
Comran Morshed2a97bc82016-01-16 17:27:01 +000021}
22
Austin Schuh09c2b0b2016-02-13 15:53:16 -080023void ShooterSide::set_goal(double angular_velocity_goal) {
24 loop_->mutable_next_R() << 0.0, angular_velocity_goal, 0.0;
Comran Morshedcde50322016-01-18 15:10:36 +000025}
Comran Morshed2a97bc82016-01-16 17:27:01 +000026
Austin Schuh09c2b0b2016-02-13 15:53:16 -080027void ShooterSide::set_position(double current_position) {
Comran Morshedcde50322016-01-18 15:10:36 +000028 // Update position in the model.
Austin Schuh09c2b0b2016-02-13 15:53:16 -080029 Y_ << current_position;
Comran Morshed2a97bc82016-01-16 17:27:01 +000030
Comran Morshedcde50322016-01-18 15:10:36 +000031 // Add the position to the history.
Austin Schuh09c2b0b2016-02-13 15:53:16 -080032 history_[history_position_] = current_position;
Comran Morshedcde50322016-01-18 15:10:36 +000033 history_position_ = (history_position_ + 1) % kHistoryLength;
34}
Comran Morshed2a97bc82016-01-16 17:27:01 +000035
James Kuszmaul651fc3f2019-05-15 21:14:25 -070036double ShooterSide::voltage() const { return loop_->U(0, 0); }
Comran Morshedcde50322016-01-18 15:10:36 +000037
Austin Schuh09c2b0b2016-02-13 15:53:16 -080038void ShooterSide::Update(bool disabled) {
39 loop_->mutable_R() = loop_->next_R();
40 if (loop_->R(1, 0) < 1.0) {
41 // Kill power at low angular velocities.
42 disabled = true;
43 }
44
45 loop_->Correct(Y_);
46 loop_->Update(disabled);
Comran Morshedcde50322016-01-18 15:10:36 +000047}
48
Alex Perrycb7da4b2019-08-28 19:35:56 -070049flatbuffers::Offset<ShooterSideStatus> ShooterSide::SetStatus(
50 flatbuffers::FlatBufferBuilder *fbb) {
51 ShooterSideStatus::Builder shooter_side_status_builder(*fbb);
Austin Schuh09c2b0b2016-02-13 15:53:16 -080052 // Compute the oldest point in the history.
53 const int oldest_history_position =
54 ((history_position_ == 0) ? kHistoryLength : history_position_) - 1;
Comran Morshedcde50322016-01-18 15:10:36 +000055
Austin Schuh09c2b0b2016-02-13 15:53:16 -080056 // Compute the distance moved over that time period.
Alex Perrycb7da4b2019-08-28 19:35:56 -070057 const double avg_angular_velocity =
Austin Schuh09c2b0b2016-02-13 15:53:16 -080058 (history_[oldest_history_position] - history_[history_position_]) /
James Kuszmaul651fc3f2019-05-15 21:14:25 -070059 (::aos::time::DurationInSeconds(::aos::controls::kLoopFrequency) *
Austin Schuh09c2b0b2016-02-13 15:53:16 -080060 static_cast<double>(kHistoryLength - 1));
Alex Perrycb7da4b2019-08-28 19:35:56 -070061 shooter_side_status_builder.add_avg_angular_velocity(avg_angular_velocity);
Austin Schuh09c2b0b2016-02-13 15:53:16 -080062
Alex Perrycb7da4b2019-08-28 19:35:56 -070063 shooter_side_status_builder.add_angular_velocity(loop_->X_hat(1, 0));
Austin Schuh09c2b0b2016-02-13 15:53:16 -080064
65 // Ready if average angular velocity is close to the goal.
Alex Perrycb7da4b2019-08-28 19:35:56 -070066 shooter_side_status_builder.add_ready(
67 (std::abs(loop_->next_R(1, 0) - avg_angular_velocity) < kTolerance &&
68 loop_->next_R(1, 0) > 1.0));
69
70 return shooter_side_status_builder.Finish();
Austin Schuh09c2b0b2016-02-13 15:53:16 -080071}
72
Austin Schuh55a13dc2019-01-27 22:39:03 -080073Shooter::Shooter(::aos::EventLoop *event_loop, const ::std::string &name)
Alex Perrycb7da4b2019-08-28 19:35:56 -070074 : aos::controls::ControlLoop<Goal, Position, Status, Output>(event_loop,
75 name),
Austin Schuhf59b8ee2016-03-19 21:31:36 -070076 shots_(0),
Austin Schuh94a54102016-11-26 15:14:35 -080077 last_pre_shot_timeout_(::aos::monotonic_clock::min_time) {}
Austin Schuh09c2b0b2016-02-13 15:53:16 -080078
Alex Perrycb7da4b2019-08-28 19:35:56 -070079void Shooter::RunIteration(const Goal *goal, const Position *position,
80 aos::Sender<Output>::Builder *output,
81 aos::Sender<Status>::Builder *status) {
Austin Schuh13d68162019-07-07 20:46:44 -070082 const ::aos::monotonic_clock::time_point monotonic_now =
83 event_loop()->monotonic_now();
Comran Morshedcde50322016-01-18 15:10:36 +000084 if (goal) {
85 // Update position/goal for our two shooter sides.
Alex Perrycb7da4b2019-08-28 19:35:56 -070086 left_.set_goal(goal->angular_velocity());
87 right_.set_goal(goal->angular_velocity());
Comran Morshedcde50322016-01-18 15:10:36 +000088 }
89
Alex Perrycb7da4b2019-08-28 19:35:56 -070090 left_.set_position(position->theta_left());
91 right_.set_position(position->theta_right());
Comran Morshedcde50322016-01-18 15:10:36 +000092
Austin Schuh09c2b0b2016-02-13 15:53:16 -080093 left_.Update(output == nullptr);
94 right_.Update(output == nullptr);
Comran Morshedcde50322016-01-18 15:10:36 +000095
Alex Perrycb7da4b2019-08-28 19:35:56 -070096 flatbuffers::Offset<ShooterSideStatus> left_status_offset =
97 left_.SetStatus(status->fbb());
98 flatbuffers::Offset<ShooterSideStatus> right_status_offset =
99 right_.SetStatus(status->fbb());
100
101 ShooterSideStatus *left_status =
102 GetMutableTemporaryPointer(*status->fbb(), left_status_offset);
103 ShooterSideStatus *right_status =
104 GetMutableTemporaryPointer(*status->fbb(), right_status_offset);
105
106 const bool ready = (left_status->ready() && right_status->ready());
107
108 Status::Builder status_builder = status->MakeBuilder<Status>();
109 status_builder.add_ready((left_status->ready() && right_status->ready()));
110 status_builder.add_left(left_status_offset);
111 status_builder.add_right(right_status_offset);
Comran Morshed2a97bc82016-01-16 17:27:01 +0000112
113 if (output) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700114 Output::Builder output_builder = output->MakeBuilder<Output>();
Comran Morshedb79c4242016-02-06 18:27:26 +0000115
Alex Perrycb7da4b2019-08-28 19:35:56 -0700116 output_builder.add_voltage_left(left_.voltage());
117 output_builder.add_voltage_right(right_.voltage());
118 // Turn the lights on if we are supposed to spin.
Comran Morshedb79c4242016-02-06 18:27:26 +0000119 if (goal) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700120 bool lights_on = false;
121 if (::std::abs(goal->angular_velocity()) > 0.0) {
122 lights_on = true;
123 if (goal->shooting_forwards()) {
124 output_builder.add_forwards_flashlight(true);
125 output_builder.add_backwards_flashlight(false);
126 } else {
127 output_builder.add_forwards_flashlight(false);
128 output_builder.add_backwards_flashlight(true);
129 }
130 }
131 if (goal->force_lights_on()) {
132 lights_on = true;
133 }
134 output_builder.add_lights_on(lights_on);
135
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800136 bool shoot = false;
137 switch (state_) {
138 case ShooterLatchState::PASS_THROUGH:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700139 if (goal->push_to_shooter()) {
140 if (::std::abs(goal->angular_velocity()) > 10) {
141 if (ready) {
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800142 state_ = ShooterLatchState::WAITING_FOR_SPINDOWN;
143 shoot = true;
144 }
145 } else {
146 shoot = true;
147 }
148 }
Austin Schuh13d68162019-07-07 20:46:44 -0700149 last_pre_shot_timeout_ = monotonic_now + chrono::seconds(1);
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800150 break;
151 case ShooterLatchState::WAITING_FOR_SPINDOWN:
152 shoot = true;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700153 if (left_.velocity() < goal->angular_velocity() * 0.9 ||
154 right_.velocity() < goal->angular_velocity() * 0.9) {
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800155 state_ = ShooterLatchState::WAITING_FOR_SPINUP;
156 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700157 if (::std::abs(goal->angular_velocity()) < 10 ||
Austin Schuh13d68162019-07-07 20:46:44 -0700158 last_pre_shot_timeout_ < monotonic_now) {
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700159 state_ = ShooterLatchState::INCREMENT_SHOT_COUNT;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800160 }
161 break;
162 case ShooterLatchState::WAITING_FOR_SPINUP:
163 shoot = true;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700164 if (left_.velocity() > goal->angular_velocity() * 0.95 &&
165 right_.velocity() > goal->angular_velocity() * 0.95) {
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700166 state_ = ShooterLatchState::INCREMENT_SHOT_COUNT;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800167 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700168 if (::std::abs(goal->angular_velocity()) < 10 ||
Austin Schuh13d68162019-07-07 20:46:44 -0700169 last_pre_shot_timeout_ < monotonic_now) {
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700170 state_ = ShooterLatchState::INCREMENT_SHOT_COUNT;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800171 }
172 break;
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700173 case ShooterLatchState::INCREMENT_SHOT_COUNT:
174 ++shots_;
175 state_ = ShooterLatchState::WAITING_FOR_SHOT_NEGEDGE;
176 break;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800177 case ShooterLatchState::WAITING_FOR_SHOT_NEGEDGE:
178 shoot = true;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700179 if (!goal->push_to_shooter()) {
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800180 state_ = ShooterLatchState::PASS_THROUGH;
181 }
182 break;
183 }
184
Alex Perrycb7da4b2019-08-28 19:35:56 -0700185 output_builder.add_clamp_open(goal->clamp_open());
186 output_builder.add_push_to_shooter(shoot);
Comran Morshedb79c4242016-02-06 18:27:26 +0000187 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700188
189 output->Send(output_builder.Finish());
Comran Morshed2a97bc82016-01-16 17:27:01 +0000190 }
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700191
Alex Perrycb7da4b2019-08-28 19:35:56 -0700192 status_builder.add_shots(shots_);
193
194 status->Send(status_builder.Finish());
Comran Morshed2a97bc82016-01-16 17:27:01 +0000195}
196
Austin Schuh09c2b0b2016-02-13 15:53:16 -0800197} // namespace shooter
Comran Morshed2a97bc82016-01-16 17:27:01 +0000198} // namespace control_loops
199} // namespace y2016