blob: 9a46906b1e331f560ad8e30df5324c0d26e0c286 [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 {
12
Comran Morshedcde50322016-01-18 15:10:36 +000013ShooterSide::ShooterSide()
14 : loop_(new StateFeedbackLoop<2, 1, 1>(
15 ::y2016::control_loops::shooter::MakeShooterLoop())) {
Comran Morshed2a97bc82016-01-16 17:27:01 +000016 memset(history_, 0, sizeof(history_));
17}
18
Comran Morshedcde50322016-01-18 15:10:36 +000019void ShooterSide::SetGoal(double angular_velocity_goal_uncapped) {
20 angular_velocity_goal_ = std::min(angular_velocity_goal_uncapped,
21 kMaxSpeed);
22}
Comran Morshed2a97bc82016-01-16 17:27:01 +000023
Comran Morshedcde50322016-01-18 15:10:36 +000024void ShooterSide::EstimatePositionTimestep() {
25 // NULL position, so look at the loop.
26 SetPosition(loop_->X_hat(0, 0));
27}
Comran Morshed2a97bc82016-01-16 17:27:01 +000028
Comran Morshedcde50322016-01-18 15:10:36 +000029void ShooterSide::SetPosition(double current_position) {
30 current_position_ = current_position;
Comran Morshed2a97bc82016-01-16 17:27:01 +000031
32 // Track the current position if the velocity goal is small.
Comran Morshedcde50322016-01-18 15:10:36 +000033 if (angular_velocity_goal_ <= 1.0) position_goal_ = current_position_;
Comran Morshed2a97bc82016-01-16 17:27:01 +000034
Comran Morshedcde50322016-01-18 15:10:36 +000035 // Update position in the model.
Comran Morshed2a97bc82016-01-16 17:27:01 +000036 Eigen::Matrix<double, 1, 1> Y;
Comran Morshedcde50322016-01-18 15:10:36 +000037 Y << current_position_;
Comran Morshed2a97bc82016-01-16 17:27:01 +000038 loop_->Correct(Y);
39
Comran Morshed2a97bc82016-01-16 17:27:01 +000040 // Prevents integral windup by limiting the position error such that the
41 // error can't produce much more than full power.
Comran Morshed2a97bc82016-01-16 17:27:01 +000042 const double max_reference =
43 (loop_->U_max(0, 0) -
Comran Morshedcde50322016-01-18 15:10:36 +000044 kAngularVelocityWeightScalar *
45 (angular_velocity_goal_ - loop_->X_hat(1, 0)) * loop_->K(0, 1)) /
Comran Morshed2a97bc82016-01-16 17:27:01 +000046 loop_->K(0, 0) +
47 loop_->X_hat(0, 0);
48 const double min_reference =
49 (loop_->U_min(0, 0) -
Comran Morshedcde50322016-01-18 15:10:36 +000050 kAngularVelocityWeightScalar *
51 (angular_velocity_goal_ - loop_->X_hat(1, 0)) * loop_->K(0, 1)) /
Comran Morshed2a97bc82016-01-16 17:27:01 +000052 loop_->K(0, 0) +
53 loop_->X_hat(0, 0);
Comran Morshed2a97bc82016-01-16 17:27:01 +000054 position_goal_ =
55 ::std::max(::std::min(position_goal_, max_reference), min_reference);
Comran Morshed2a97bc82016-01-16 17:27:01 +000056
Comran Morshedcde50322016-01-18 15:10:36 +000057 loop_->mutable_R() << position_goal_, angular_velocity_goal_;
58 position_goal_ +=
59 angular_velocity_goal_ * ::aos::controls::kLoopFrequency.ToSeconds();
Comran Morshed2a97bc82016-01-16 17:27:01 +000060
Comran Morshedcde50322016-01-18 15:10:36 +000061 // Add the position to the history.
62 history_[history_position_] = current_position_;
63 history_position_ = (history_position_ + 1) % kHistoryLength;
64}
Comran Morshed2a97bc82016-01-16 17:27:01 +000065
Comran Morshedcde50322016-01-18 15:10:36 +000066const ShooterStatus ShooterSide::GetStatus() {
67 // Calculate average over dt * kHistoryLength.
Comran Morshed2a97bc82016-01-16 17:27:01 +000068 int old_history_position =
69 ((history_position_ == 0) ? kHistoryLength : history_position_) - 1;
Comran Morshedcde50322016-01-18 15:10:36 +000070 double avg_angular_velocity =
71 (history_[old_history_position] - history_[history_position_]) /
72 ::aos::controls::kLoopFrequency.ToSeconds() /
73 static_cast<double>(kHistoryLength - 1);
Comran Morshed2a97bc82016-01-16 17:27:01 +000074
Comran Morshedcde50322016-01-18 15:10:36 +000075 // Ready if average angular velocity is close to the goal.
76 bool ready = (std::abs(angular_velocity_goal_ - avg_angular_velocity) <
77 kTolerance &&
78 angular_velocity_goal_ != 0.0);
Comran Morshed2a97bc82016-01-16 17:27:01 +000079
Comran Morshedcde50322016-01-18 15:10:36 +000080 return {avg_angular_velocity, ready};
81}
82
83double ShooterSide::GetOutput() {
84 if (angular_velocity_goal_ < 1.0) {
85 // Kill power at low angular velocities.
86 return 0.0;
Comran Morshed2a97bc82016-01-16 17:27:01 +000087 }
Comran Morshed2a97bc82016-01-16 17:27:01 +000088
Comran Morshedcde50322016-01-18 15:10:36 +000089 return loop_->U(0, 0);
90}
91
92void ShooterSide::UpdateLoop(bool output_is_null) {
93 loop_->Update(output_is_null);
94}
95
96Shooter::Shooter(control_loops::ShooterQueue *my_shooter)
97 : aos::controls::ControlLoop<control_loops::ShooterQueue>(my_shooter) {}
98
99void Shooter::RunIteration(
100 const control_loops::ShooterQueue::Goal *goal,
101 const control_loops::ShooterQueue::Position *position,
102 control_loops::ShooterQueue::Output *output,
103 control_loops::ShooterQueue::Status *status) {
104 if (goal) {
105 // Update position/goal for our two shooter sides.
106 left_.SetGoal(goal->angular_velocity_left);
107 right_.SetGoal(goal->angular_velocity_right);
108
109 if (position == nullptr) {
110 left_.EstimatePositionTimestep();
111 right_.EstimatePositionTimestep();
112 } else {
113 left_.SetPosition(position->theta_left);
114 right_.SetPosition(position->theta_right);
115 }
116 }
117
118 ShooterStatus status_left = left_.GetStatus();
119 ShooterStatus status_right = right_.GetStatus();
120 status->avg_angular_velocity_left = status_left.avg_angular_velocity;
121 status->avg_angular_velocity_right = status_right.avg_angular_velocity;
122
123 status->ready_left = status_left.ready;
124 status->ready_right = status_right.ready;
125 status->ready_both = (status_left.ready && status_right.ready);
126
127 left_.UpdateLoop(output == nullptr);
128 right_.UpdateLoop(output == nullptr);
Comran Morshed2a97bc82016-01-16 17:27:01 +0000129
130 if (output) {
Comran Morshedcde50322016-01-18 15:10:36 +0000131 output->voltage_left = left_.GetOutput();
132 output->voltage_right = right_.GetOutput();
Comran Morshed2a97bc82016-01-16 17:27:01 +0000133 }
134}
135
136} // namespace control_loops
137} // namespace y2016