blob: 699903dd09d519a489d998fcc96c1f0297aca4fb [file] [log] [blame]
Comran Morshed2a97bc82016-01-16 17:27:01 +00001#include "y2016/control_loops/shooter/shooter.h"
2
3#include "aos/common/controls/control_loops.q.h"
4#include "aos/common/logging/logging.h"
5#include "aos/common/logging/queue_logging.h"
6
7#include "y2016/control_loops/shooter/shooter_plant.h"
8
Comran Morshedcde50322016-01-18 15:10:36 +00009
Comran Morshed2a97bc82016-01-16 17:27:01 +000010namespace y2016 {
11namespace control_loops {
Austin Schuh09c2b0b2016-02-13 15:53:16 -080012namespace shooter {
13
Austin Schuh7eecd7c2016-02-28 21:59:05 -080014using ::aos::time::Time;
15
Austin Schuh09c2b0b2016-02-13 15:53:16 -080016// TODO(austin): Pseudo current limit?
Comran Morshed2a97bc82016-01-16 17:27:01 +000017
Comran Morshedcde50322016-01-18 15:10:36 +000018ShooterSide::ShooterSide()
Austin Schuh09c2b0b2016-02-13 15:53:16 -080019 : loop_(new StateFeedbackLoop<3, 1, 1>(MakeIntegralShooterLoop())) {
20 history_.fill(0);
21 Y_.setZero();
Comran Morshed2a97bc82016-01-16 17:27:01 +000022}
23
Austin Schuh09c2b0b2016-02-13 15:53:16 -080024void ShooterSide::set_goal(double angular_velocity_goal) {
25 loop_->mutable_next_R() << 0.0, angular_velocity_goal, 0.0;
Comran Morshedcde50322016-01-18 15:10:36 +000026}
Comran Morshed2a97bc82016-01-16 17:27:01 +000027
Austin Schuh09c2b0b2016-02-13 15:53:16 -080028void ShooterSide::set_position(double current_position) {
Comran Morshedcde50322016-01-18 15:10:36 +000029 // Update position in the model.
Austin Schuh09c2b0b2016-02-13 15:53:16 -080030 Y_ << current_position;
Comran Morshed2a97bc82016-01-16 17:27:01 +000031
Comran Morshedcde50322016-01-18 15:10:36 +000032 // Add the position to the history.
Austin Schuh09c2b0b2016-02-13 15:53:16 -080033 history_[history_position_] = current_position;
Comran Morshedcde50322016-01-18 15:10:36 +000034 history_position_ = (history_position_ + 1) % kHistoryLength;
35}
Comran Morshed2a97bc82016-01-16 17:27:01 +000036
Austin Schuh09c2b0b2016-02-13 15:53:16 -080037double ShooterSide::voltage() const {
Comran Morshedcde50322016-01-18 15:10:36 +000038 return loop_->U(0, 0);
39}
40
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_]) /
60 (::aos::controls::kLoopFrequency.ToSeconds() *
61 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
71Shooter::Shooter(ShooterQueue *my_shooter)
Austin Schuh7eecd7c2016-02-28 21:59:05 -080072 : aos::controls::ControlLoop<ShooterQueue>(my_shooter),
73 last_pre_shot_timeout_(0, 0) {}
Austin Schuh09c2b0b2016-02-13 15:53:16 -080074
75void Shooter::RunIteration(const ShooterQueue::Goal *goal,
76 const ShooterQueue::Position *position,
77 ShooterQueue::Output *output,
78 ShooterQueue::Status *status) {
Comran Morshedcde50322016-01-18 15:10:36 +000079 if (goal) {
80 // Update position/goal for our two shooter sides.
Austin Schuh09c2b0b2016-02-13 15:53:16 -080081 left_.set_goal(goal->angular_velocity);
82 right_.set_goal(goal->angular_velocity);
Austin Schuhe0729a62016-03-12 21:54:17 -080083
84 // Turn the lights on if we are supposed to spin.
85 if (output) {
86 if (::std::abs(goal->angular_velocity) > 0.0) {
87 output->lights_on = true;
88 }
89 }
Comran Morshedcde50322016-01-18 15:10:36 +000090 }
91
Austin Schuh09c2b0b2016-02-13 15:53:16 -080092 left_.set_position(position->theta_left);
93 right_.set_position(position->theta_right);
Comran Morshedcde50322016-01-18 15:10:36 +000094
Austin Schuh09c2b0b2016-02-13 15:53:16 -080095 left_.Update(output == nullptr);
96 right_.Update(output == nullptr);
Comran Morshedcde50322016-01-18 15:10:36 +000097
Austin Schuh09c2b0b2016-02-13 15:53:16 -080098 left_.SetStatus(&status->left);
99 right_.SetStatus(&status->right);
100 status->ready = (status->left.ready && status->right.ready);
Comran Morshed2a97bc82016-01-16 17:27:01 +0000101
102 if (output) {
Austin Schuh09c2b0b2016-02-13 15:53:16 -0800103 output->voltage_left = left_.voltage();
104 output->voltage_right = right_.voltage();
Comran Morshedb79c4242016-02-06 18:27:26 +0000105
106 if (goal) {
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800107 bool shoot = false;
108 switch (state_) {
109 case ShooterLatchState::PASS_THROUGH:
110 if (goal->push_to_shooter) {
111 if (::std::abs(goal->angular_velocity) > 10) {
112 if (status->ready) {
113 state_ = ShooterLatchState::WAITING_FOR_SPINDOWN;
114 shoot = true;
115 }
116 } else {
117 shoot = true;
118 }
119 }
120 last_pre_shot_timeout_ = Time::Now() + Time::InSeconds(1.0);
121 break;
122 case ShooterLatchState::WAITING_FOR_SPINDOWN:
123 shoot = true;
124 if (left_.velocity() < goal->angular_velocity * 0.9 ||
125 right_.velocity() < goal->angular_velocity * 0.9) {
126 state_ = ShooterLatchState::WAITING_FOR_SPINUP;
127 }
128 if (::std::abs(goal->angular_velocity) < 10 ||
129 last_pre_shot_timeout_ < Time::Now()) {
130 state_ = ShooterLatchState::WAITING_FOR_SHOT_NEGEDGE;
131 }
132 break;
133 case ShooterLatchState::WAITING_FOR_SPINUP:
134 shoot = true;
135 if (left_.velocity() > goal->angular_velocity * 0.95 &&
136 right_.velocity() > goal->angular_velocity * 0.95) {
137 state_ = ShooterLatchState::WAITING_FOR_SHOT_NEGEDGE;
138 }
139 if (::std::abs(goal->angular_velocity) < 10 ||
140 last_pre_shot_timeout_ < Time::Now()) {
141 state_ = ShooterLatchState::WAITING_FOR_SHOT_NEGEDGE;
142 }
143 break;
144 case ShooterLatchState::WAITING_FOR_SHOT_NEGEDGE:
145 shoot = true;
146 if (!goal->push_to_shooter) {
147 state_ = ShooterLatchState::PASS_THROUGH;
148 }
149 break;
150 }
151
Comran Morshedb79c4242016-02-06 18:27:26 +0000152 output->clamp_open = goal->clamp_open;
Austin Schuh7eecd7c2016-02-28 21:59:05 -0800153 output->push_to_shooter = shoot;
Comran Morshedb79c4242016-02-06 18:27:26 +0000154 }
Comran Morshed2a97bc82016-01-16 17:27:01 +0000155 }
156}
157
Austin Schuh09c2b0b2016-02-13 15:53:16 -0800158} // namespace shooter
Comran Morshed2a97bc82016-01-16 17:27:01 +0000159} // namespace control_loops
160} // namespace y2016