blob: 6ae7f0eff0ff81450aa71f8150411c4b17b723bb [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
Comran Morshedcde50322016-01-18 15:10:36 +000011
Comran Morshed2a97bc82016-01-16 17:27:01 +000012namespace y2016 {
13namespace control_loops {
Austin Schuh09c2b0b2016-02-13 15:53:16 -080014namespace shooter {
15
Austin Schuh214e9c12016-11-25 17:26:20 -080016namespace chrono = ::std::chrono;
Austin Schuh94a54102016-11-26 15:14:35 -080017using ::aos::monotonic_clock;
Austin Schuh7eecd7c2016-02-28 21:59:05 -080018
Austin Schuh09c2b0b2016-02-13 15:53:16 -080019// TODO(austin): Pseudo current limit?
Comran Morshed2a97bc82016-01-16 17:27:01 +000020
Comran Morshedcde50322016-01-18 15:10:36 +000021ShooterSide::ShooterSide()
Austin Schuh09c2b0b2016-02-13 15:53:16 -080022 : loop_(new StateFeedbackLoop<3, 1, 1>(MakeIntegralShooterLoop())) {
23 history_.fill(0);
24 Y_.setZero();
Comran Morshed2a97bc82016-01-16 17:27:01 +000025}
26
Austin Schuh09c2b0b2016-02-13 15:53:16 -080027void ShooterSide::set_goal(double angular_velocity_goal) {
28 loop_->mutable_next_R() << 0.0, angular_velocity_goal, 0.0;
Comran Morshedcde50322016-01-18 15:10:36 +000029}
Comran Morshed2a97bc82016-01-16 17:27:01 +000030
Austin Schuh09c2b0b2016-02-13 15:53:16 -080031void ShooterSide::set_position(double current_position) {
Comran Morshedcde50322016-01-18 15:10:36 +000032 // Update position in the model.
Austin Schuh09c2b0b2016-02-13 15:53:16 -080033 Y_ << current_position;
Comran Morshed2a97bc82016-01-16 17:27:01 +000034
Comran Morshedcde50322016-01-18 15:10:36 +000035 // Add the position to the history.
Austin Schuh09c2b0b2016-02-13 15:53:16 -080036 history_[history_position_] = current_position;
Comran Morshedcde50322016-01-18 15:10:36 +000037 history_position_ = (history_position_ + 1) % kHistoryLength;
38}
Comran Morshed2a97bc82016-01-16 17:27:01 +000039
Austin Schuh09c2b0b2016-02-13 15:53:16 -080040double ShooterSide::voltage() const {
Comran Morshedcde50322016-01-18 15:10:36 +000041 return loop_->U(0, 0);
42}
43
Austin Schuh09c2b0b2016-02-13 15:53:16 -080044void ShooterSide::Update(bool disabled) {
45 loop_->mutable_R() = loop_->next_R();
46 if (loop_->R(1, 0) < 1.0) {
47 // Kill power at low angular velocities.
48 disabled = true;
49 }
50
51 loop_->Correct(Y_);
52 loop_->Update(disabled);
Comran Morshedcde50322016-01-18 15:10:36 +000053}
54
Austin Schuh09c2b0b2016-02-13 15:53:16 -080055void ShooterSide::SetStatus(ShooterSideStatus *status) {
56 // Compute the oldest point in the history.
57 const int oldest_history_position =
58 ((history_position_ == 0) ? kHistoryLength : history_position_) - 1;
Comran Morshedcde50322016-01-18 15:10:36 +000059
Austin Schuh09c2b0b2016-02-13 15:53:16 -080060 // Compute the distance moved over that time period.
61 status->avg_angular_velocity =
62 (history_[oldest_history_position] - history_[history_position_]) /
Austin Schuh214e9c12016-11-25 17:26:20 -080063 (chrono::duration_cast<chrono::duration<double>>(
64 ::aos::controls::kLoopFrequency).count() *
Austin Schuh09c2b0b2016-02-13 15:53:16 -080065 static_cast<double>(kHistoryLength - 1));
66
67 status->angular_velocity = loop_->X_hat(1, 0);
68
69 // Ready if average angular velocity is close to the goal.
70 status->ready = (std::abs(loop_->next_R(1, 0) -
71 status->avg_angular_velocity) < kTolerance &&
72 loop_->next_R(1, 0) > 1.0);
73}
74
Austin Schuh55a13dc2019-01-27 22:39:03 -080075Shooter::Shooter(::aos::EventLoop *event_loop, const ::std::string &name)
76 : aos::controls::ControlLoop<ShooterQueue>(event_loop, name),
Austin Schuhf59b8ee2016-03-19 21:31:36 -070077 shots_(0),
Austin Schuh94a54102016-11-26 15:14:35 -080078 last_pre_shot_timeout_(::aos::monotonic_clock::min_time) {}
Austin Schuh09c2b0b2016-02-13 15:53:16 -080079
80void Shooter::RunIteration(const ShooterQueue::Goal *goal,
81 const ShooterQueue::Position *position,
82 ShooterQueue::Output *output,
83 ShooterQueue::Status *status) {
Comran Morshedcde50322016-01-18 15:10:36 +000084 if (goal) {
85 // Update position/goal for our two shooter sides.
Austin Schuh09c2b0b2016-02-13 15:53:16 -080086 left_.set_goal(goal->angular_velocity);
87 right_.set_goal(goal->angular_velocity);
Austin Schuhe0729a62016-03-12 21:54:17 -080088
89 // Turn the lights on if we are supposed to spin.
90 if (output) {
Austin Schuhb2c33382016-04-03 16:09:17 -070091 if (::std::abs(goal->angular_velocity) > 0.0) {
92 output->lights_on = true;
93 if (goal->shooting_forwards) {
94 output->forwards_flashlight = true;
95 output->backwards_flashlight = false;
96 } else {
97 output->forwards_flashlight = false;
98 output->backwards_flashlight = true;
99 }
100 }
101 if (goal->force_lights_on) {
Austin Schuhe0729a62016-03-12 21:54:17 -0800102 output->lights_on = true;
103 }
104 }
Comran Morshedcde50322016-01-18 15:10:36 +0000105 }
106
Austin Schuh09c2b0b2016-02-13 15:53:16 -0800107 left_.set_position(position->theta_left);
108 right_.set_position(position->theta_right);
Comran Morshedcde50322016-01-18 15:10:36 +0000109
Austin Schuh09c2b0b2016-02-13 15:53:16 -0800110 left_.Update(output == nullptr);
111 right_.Update(output == nullptr);
Comran Morshedcde50322016-01-18 15:10:36 +0000112
Austin Schuh09c2b0b2016-02-13 15:53:16 -0800113 left_.SetStatus(&status->left);
114 right_.SetStatus(&status->right);
115 status->ready = (status->left.ready && status->right.ready);
Comran Morshed2a97bc82016-01-16 17:27:01 +0000116
117 if (output) {
Austin Schuh09c2b0b2016-02-13 15:53:16 -0800118 output->voltage_left = left_.voltage();
119 output->voltage_right = right_.voltage();
Comran Morshedb79c4242016-02-06 18:27:26 +0000120
121 if (goal) {
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800122 bool shoot = false;
123 switch (state_) {
124 case ShooterLatchState::PASS_THROUGH:
125 if (goal->push_to_shooter) {
126 if (::std::abs(goal->angular_velocity) > 10) {
127 if (status->ready) {
128 state_ = ShooterLatchState::WAITING_FOR_SPINDOWN;
129 shoot = true;
130 }
131 } else {
132 shoot = true;
133 }
134 }
Austin Schuh94a54102016-11-26 15:14:35 -0800135 last_pre_shot_timeout_ = monotonic_clock::now() + chrono::seconds(1);
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800136 break;
137 case ShooterLatchState::WAITING_FOR_SPINDOWN:
138 shoot = true;
139 if (left_.velocity() < goal->angular_velocity * 0.9 ||
140 right_.velocity() < goal->angular_velocity * 0.9) {
141 state_ = ShooterLatchState::WAITING_FOR_SPINUP;
142 }
143 if (::std::abs(goal->angular_velocity) < 10 ||
Austin Schuh94a54102016-11-26 15:14:35 -0800144 last_pre_shot_timeout_ < monotonic_clock::now()) {
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700145 state_ = ShooterLatchState::INCREMENT_SHOT_COUNT;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800146 }
147 break;
148 case ShooterLatchState::WAITING_FOR_SPINUP:
149 shoot = true;
150 if (left_.velocity() > goal->angular_velocity * 0.95 &&
151 right_.velocity() > goal->angular_velocity * 0.95) {
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700152 state_ = ShooterLatchState::INCREMENT_SHOT_COUNT;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800153 }
154 if (::std::abs(goal->angular_velocity) < 10 ||
Austin Schuh94a54102016-11-26 15:14:35 -0800155 last_pre_shot_timeout_ < monotonic_clock::now()) {
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700156 state_ = ShooterLatchState::INCREMENT_SHOT_COUNT;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800157 }
158 break;
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700159 case ShooterLatchState::INCREMENT_SHOT_COUNT:
160 ++shots_;
161 state_ = ShooterLatchState::WAITING_FOR_SHOT_NEGEDGE;
162 break;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800163 case ShooterLatchState::WAITING_FOR_SHOT_NEGEDGE:
164 shoot = true;
165 if (!goal->push_to_shooter) {
166 state_ = ShooterLatchState::PASS_THROUGH;
167 }
168 break;
169 }
170
Comran Morshedb79c4242016-02-06 18:27:26 +0000171 output->clamp_open = goal->clamp_open;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800172 output->push_to_shooter = shoot;
Comran Morshedb79c4242016-02-06 18:27:26 +0000173 }
Comran Morshed2a97bc82016-01-16 17:27:01 +0000174 }
Austin Schuhf59b8ee2016-03-19 21:31:36 -0700175
176 status->shots = shots_;
Comran Morshed2a97bc82016-01-16 17:27:01 +0000177}
178
Austin Schuh09c2b0b2016-02-13 15:53:16 -0800179} // namespace shooter
Comran Morshed2a97bc82016-01-16 17:27:01 +0000180} // namespace control_loops
181} // namespace y2016