blob: bf527ece8ea2190e011c9d34dbb3d7987af74eb3 [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/controls/control_loops.q.h"
6#include "aos/logging/logging.h"
7#include "aos/logging/queue_logging.h"
Comran Morshed2a97bc82016-01-16 17:27:01 +00008
9#include "y2016/control_loops/shooter/shooter_plant.h"
10
11namespace y2016 {
12namespace control_loops {
Austin Schuh09c2b0b2016-02-13 15:53:16 -080013namespace shooter {
14
Austin Schuh214e9c12016-11-25 17:26:20 -080015namespace chrono = ::std::chrono;
Austin Schuh94a54102016-11-26 15:14:35 -080016using ::aos::monotonic_clock;
Austin Schuh7eecd7c2016-02-28 21:59:05 -080017
Austin Schuh09c2b0b2016-02-13 15:53:16 -080018// TODO(austin): Pseudo current limit?
Comran Morshed2a97bc82016-01-16 17:27:01 +000019
Comran Morshedcde50322016-01-18 15:10:36 +000020ShooterSide::ShooterSide()
Austin Schuh09c2b0b2016-02-13 15:53:16 -080021 : loop_(new StateFeedbackLoop<3, 1, 1>(MakeIntegralShooterLoop())) {
22 history_.fill(0);
23 Y_.setZero();
Comran Morshed2a97bc82016-01-16 17:27:01 +000024}
25
Austin Schuh09c2b0b2016-02-13 15:53:16 -080026void ShooterSide::set_goal(double angular_velocity_goal) {
27 loop_->mutable_next_R() << 0.0, angular_velocity_goal, 0.0;
Comran Morshedcde50322016-01-18 15:10:36 +000028}
Comran Morshed2a97bc82016-01-16 17:27:01 +000029
Austin Schuh09c2b0b2016-02-13 15:53:16 -080030void ShooterSide::set_position(double current_position) {
Comran Morshedcde50322016-01-18 15:10:36 +000031 // Update position in the model.
Austin Schuh09c2b0b2016-02-13 15:53:16 -080032 Y_ << current_position;
Comran Morshed2a97bc82016-01-16 17:27:01 +000033
Comran Morshedcde50322016-01-18 15:10:36 +000034 // Add the position to the history.
Austin Schuh09c2b0b2016-02-13 15:53:16 -080035 history_[history_position_] = current_position;
Comran Morshedcde50322016-01-18 15:10:36 +000036 history_position_ = (history_position_ + 1) % kHistoryLength;
37}
Comran Morshed2a97bc82016-01-16 17:27:01 +000038
James Kuszmaul651fc3f2019-05-15 21:14:25 -070039double ShooterSide::voltage() const { return loop_->U(0, 0); }
Comran Morshedcde50322016-01-18 15:10:36 +000040
Austin Schuh09c2b0b2016-02-13 15:53:16 -080041void ShooterSide::Update(bool disabled) {
42 loop_->mutable_R() = loop_->next_R();
43 if (loop_->R(1, 0) < 1.0) {
44 // Kill power at low angular velocities.
45 disabled = true;
46 }
47
48 loop_->Correct(Y_);
49 loop_->Update(disabled);
Comran Morshedcde50322016-01-18 15:10:36 +000050}
51
Austin Schuh09c2b0b2016-02-13 15:53:16 -080052void ShooterSide::SetStatus(ShooterSideStatus *status) {
53 // Compute the oldest point in the history.
54 const int oldest_history_position =
55 ((history_position_ == 0) ? kHistoryLength : history_position_) - 1;
Comran Morshedcde50322016-01-18 15:10:36 +000056
Austin Schuh09c2b0b2016-02-13 15:53:16 -080057 // Compute the distance moved over that time period.
58 status->avg_angular_velocity =
59 (history_[oldest_history_position] - history_[history_position_]) /
James Kuszmaul651fc3f2019-05-15 21:14:25 -070060 (::aos::time::DurationInSeconds(::aos::controls::kLoopFrequency) *
Austin Schuh09c2b0b2016-02-13 15:53:16 -080061 static_cast<double>(kHistoryLength - 1));
62
63 status->angular_velocity = loop_->X_hat(1, 0);
64
65 // Ready if average angular velocity is close to the goal.
66 status->ready = (std::abs(loop_->next_R(1, 0) -
67 status->avg_angular_velocity) < kTolerance &&
68 loop_->next_R(1, 0) > 1.0);
69}
70
Austin Schuh55a13dc2019-01-27 22:39:03 -080071Shooter::Shooter(::aos::EventLoop *event_loop, const ::std::string &name)
72 : aos::controls::ControlLoop<ShooterQueue>(event_loop, name),
Austin Schuhf59b8ee2016-03-19 21:31:36 -070073 shots_(0),
Austin Schuh94a54102016-11-26 15:14:35 -080074 last_pre_shot_timeout_(::aos::monotonic_clock::min_time) {}
Austin Schuh09c2b0b2016-02-13 15:53:16 -080075
76void Shooter::RunIteration(const ShooterQueue::Goal *goal,
77 const ShooterQueue::Position *position,
78 ShooterQueue::Output *output,
79 ShooterQueue::Status *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.
Austin Schuh09c2b0b2016-02-13 15:53:16 -080084 left_.set_goal(goal->angular_velocity);
85 right_.set_goal(goal->angular_velocity);
Austin Schuhe0729a62016-03-12 21:54:17 -080086
87 // Turn the lights on if we are supposed to spin.
88 if (output) {
Austin Schuhb2c33382016-04-03 16:09:17 -070089 if (::std::abs(goal->angular_velocity) > 0.0) {
90 output->lights_on = true;
91 if (goal->shooting_forwards) {
92 output->forwards_flashlight = true;
93 output->backwards_flashlight = false;
94 } else {
95 output->forwards_flashlight = false;
96 output->backwards_flashlight = true;
97 }
98 }
99 if (goal->force_lights_on) {
Austin Schuhe0729a62016-03-12 21:54:17 -0800100 output->lights_on = true;
101 }
102 }
Comran Morshedcde50322016-01-18 15:10:36 +0000103 }
104
Austin Schuh09c2b0b2016-02-13 15:53:16 -0800105 left_.set_position(position->theta_left);
106 right_.set_position(position->theta_right);
Comran Morshedcde50322016-01-18 15:10:36 +0000107
Austin Schuh09c2b0b2016-02-13 15:53:16 -0800108 left_.Update(output == nullptr);
109 right_.Update(output == nullptr);
Comran Morshedcde50322016-01-18 15:10:36 +0000110
Austin Schuh09c2b0b2016-02-13 15:53:16 -0800111 left_.SetStatus(&status->left);
112 right_.SetStatus(&status->right);
113 status->ready = (status->left.ready && status->right.ready);
Comran Morshed2a97bc82016-01-16 17:27:01 +0000114
115 if (output) {
Austin Schuh09c2b0b2016-02-13 15:53:16 -0800116 output->voltage_left = left_.voltage();
117 output->voltage_right = right_.voltage();
Comran Morshedb79c4242016-02-06 18:27:26 +0000118
119 if (goal) {
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800120 bool shoot = false;
121 switch (state_) {
122 case ShooterLatchState::PASS_THROUGH:
123 if (goal->push_to_shooter) {
124 if (::std::abs(goal->angular_velocity) > 10) {
125 if (status->ready) {
126 state_ = ShooterLatchState::WAITING_FOR_SPINDOWN;
127 shoot = true;
128 }
129 } else {
130 shoot = true;
131 }
132 }
Austin Schuh13d68162019-07-07 20:46:44 -0700133 last_pre_shot_timeout_ = monotonic_now + chrono::seconds(1);
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800134 break;
135 case ShooterLatchState::WAITING_FOR_SPINDOWN:
136 shoot = true;
137 if (left_.velocity() < goal->angular_velocity * 0.9 ||
138 right_.velocity() < goal->angular_velocity * 0.9) {
139 state_ = ShooterLatchState::WAITING_FOR_SPINUP;
140 }
141 if (::std::abs(goal->angular_velocity) < 10 ||
Austin Schuh13d68162019-07-07 20:46:44 -0700142 last_pre_shot_timeout_ < monotonic_now) {
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700143 state_ = ShooterLatchState::INCREMENT_SHOT_COUNT;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800144 }
145 break;
146 case ShooterLatchState::WAITING_FOR_SPINUP:
147 shoot = true;
148 if (left_.velocity() > goal->angular_velocity * 0.95 &&
149 right_.velocity() > goal->angular_velocity * 0.95) {
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700150 state_ = ShooterLatchState::INCREMENT_SHOT_COUNT;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800151 }
152 if (::std::abs(goal->angular_velocity) < 10 ||
Austin Schuh13d68162019-07-07 20:46:44 -0700153 last_pre_shot_timeout_ < monotonic_now) {
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700154 state_ = ShooterLatchState::INCREMENT_SHOT_COUNT;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800155 }
156 break;
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700157 case ShooterLatchState::INCREMENT_SHOT_COUNT:
158 ++shots_;
159 state_ = ShooterLatchState::WAITING_FOR_SHOT_NEGEDGE;
160 break;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800161 case ShooterLatchState::WAITING_FOR_SHOT_NEGEDGE:
162 shoot = true;
163 if (!goal->push_to_shooter) {
164 state_ = ShooterLatchState::PASS_THROUGH;
165 }
166 break;
167 }
168
Comran Morshedb79c4242016-02-06 18:27:26 +0000169 output->clamp_open = goal->clamp_open;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800170 output->push_to_shooter = shoot;
Comran Morshedb79c4242016-02-06 18:27:26 +0000171 }
Comran Morshed2a97bc82016-01-16 17:27:01 +0000172 }
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700173
174 status->shots = shots_;
Comran Morshed2a97bc82016-01-16 17:27:01 +0000175}
176
Austin Schuh09c2b0b2016-02-13 15:53:16 -0800177} // namespace shooter
Comran Morshed2a97bc82016-01-16 17:27:01 +0000178} // namespace control_loops
179} // namespace y2016