blob: 08138fff048e0dc4e60b53d112a39ff8965d0bc2 [file] [log] [blame]
#include "frc971/control_loops/shooter/shooter.h"
#include <stdio.h>
#include <algorithm>
#include "aos/common/control_loop/control_loops.q.h"
#include "aos/common/control_loop/control_loops.q.h"
#include "aos/common/logging/logging.h"
#include "frc971/constants.h"
#include "frc971/control_loops/shooter/shooter_motor_plant.h"
namespace frc971 {
namespace control_loops {
using ::aos::time::Time;
void ZeroedStateFeedbackLoop::CapU() {
const double old_voltage = voltage_;
voltage_ += U(0, 0);
uncapped_voltage_ = voltage_;
// TODO(ben): Limit the voltage if we are ever not certain that things are
// working.
double limit = 12.0;
// Make sure that reality and the observer can't get too far off. There is a
// delay by one cycle between the applied voltage and X_hat(2, 0), so compare
// against last cycle's voltage.
if (X_hat(2, 0) > last_voltage_ + 2.0) {
voltage_ -= X_hat(2, 0) - (last_voltage_ + 2.0);
//LOG(DEBUG, "X_hat(2, 0) = %f\n", X_hat(2, 0));
} else if (X_hat(2, 0) < last_voltage_ - 2.0) {
voltage_ += X_hat(2, 0) - (last_voltage_ - 2.0);
//LOG(DEBUG, "X_hat(2, 0) = %f\n", X_hat(2, 0));
}
voltage_ = std::min(limit, voltage_);
voltage_ = std::max(-limit, voltage_);
U(0, 0) = voltage_ - old_voltage;
//LOG(DEBUG, "abc %f\n", X_hat(2, 0) - voltage_);
//LOG(DEBUG, "error %f\n", X_hat(0, 0) - R(0, 0));
last_voltage_ = voltage_;
}
ShooterMotor::ShooterMotor(control_loops::ShooterGroup *my_shooter)
: aos::control_loops::ControlLoop<control_loops::ShooterGroup>(my_shooter),
shooter_(MakeShooterLoop()),
calibration_position_(0.0),
state_(STATE_INITIALIZE),
loading_problem_end_time_(0, 0),
shooter_brake_set_time_(0, 0),
prepare_fire_end_time_(0, 0),
shot_end_time_(0, 0),
cycles_not_moved_(0),
initial_loop_(true) {}
// Positive is out, and positive power is out.
void ShooterMotor::RunIteration(
const control_loops::ShooterGroup::Goal *goal,
const control_loops::ShooterGroup::Position *position,
control_loops::ShooterGroup::Output *output,
control_loops::ShooterGroup::Status *status) {
constexpr double dt = 0.01;
// we must always have these or we have issues.
if (goal == NULL || status == NULL) {
if (output) output->voltage = 0;
LOG(ERROR, "Thought I would just check for null and die.\n");
return;
}
if (initial_loop_) {
// TODO(austin): If 'reset()', we are lost, start over.
initial_loop_ = false;
shooter_.SetPositionDirectly(position->position);
} else {
shooter_.SetPositionValues(position->position);
}
// Disable the motors now so that all early returns will return with the
// motors disabled.
if (output) output->voltage = 0;
const frc971::constants::Values &values = constants::GetValues();
double real_position = shooter_.position();
double adjusted_position = shooter_.position() - calibration_position_;
if (position) {
last_position_ = *position;
LOG(DEBUG,
"pos > real: %.2f adjusted: %.2f raw: %.2f calib: %.2f state= %d\n",
real_position, adjusted_position, position->position,
calibration_position_, state_);
}
// Don't even let the control loops run.
bool shooter_loop_disable = false;
// Adds voltage to take up slack in gears before shot.
bool apply_some_voltage = false;
switch (state_) {
case STATE_INITIALIZE:
// Start off with the assumption that we are at the value
// futhest back given our sensors.
if (position && position->pusher_distal.current) {
//TODO(ben): use posedge
calibration_position_ =
position->position - values.shooter.pusher_distal.lower_angle;
} else if (position && position->pusher_proximal.current) {
//TODO(ben): use posedge
calibration_position_ =
position->position - values.shooter.pusher_proximal.lower_angle;
}
state_ = STATE_REQUEST_LOAD;
// Zero out initial goal.
shooter_.SetGoalPosition(real_position, 0.0);
if (position) {
output->latch_piston = position->plunger;
} else {
// We don't know what is going on so just close the latch to be safe.
output->latch_piston = true;
}
output->brake_piston = false;
break;
case STATE_REQUEST_LOAD:
if (position->plunger && position->latch) {
// Already latched.
state_ = STATE_PREPARE_SHOT;
} else if (position->pusher_distal.current || (adjusted_position) < 0) {
state_ = STATE_LOAD_BACKTRACK;
// TODO(ben): double check that rezero is the right thing to do here
if (position) {
calibration_position_ = position->position;
}
} else {
state_ = STATE_LOAD;
}
shooter_.SetGoalPosition(0.0, 0.0);
if (position && output) {
output->latch_piston = position->plunger;
}
if (output) {
output->brake_piston = false;
}
break;
case STATE_LOAD_BACKTRACK:
if (adjusted_position > values.shooter.pusher_distal.upper_angle + 0.01) {
shooter_.SetGoalPosition(
real_position - values.shooter.zeroing_speed * dt,
values.shooter.zeroing_speed);
} else {
state_ = STATE_LOAD;
}
if (output) output->latch_piston = false;
if (output) output->brake_piston = true;
break;
case STATE_LOAD:
if (position && position->pusher_proximal.current &&
!last_position_.pusher_proximal.current) {
//TODO(ben): use posedge
calibration_position_ =
position->position - values.shooter.pusher_proximal.upper_angle;
}
if (position && position->pusher_distal.current &&
!last_position_.pusher_distal.current) {
//TODO(ben): use posedge
calibration_position_ =
position->position - values.shooter.pusher_distal.lower_angle;
}
shooter_.SetGoalPosition(calibration_position_, 0.0);
if (position && output) {
output->latch_piston = position->plunger;
}
if (position->plunger && position->latch) {
state_ = STATE_PREPARE_SHOT;
} else if (position->plunger &&
fabs(adjusted_position - PowerToPosition(goal->shot_power)) <
0.05) {
state_ = STATE_LOADING_PROBLEM;
loading_problem_end_time_ =
Time::Now(Time::kDefaultClock) + Time::InSeconds(3.0);
}
if (output) output->brake_piston = false;
break;
case STATE_LOADING_PROBLEM:
if (Time::Now() > loading_problem_end_time_) {
state_ = STATE_UNLOAD;
} else if (position->plunger && position->latch) {
state_ = STATE_PREPARE_SHOT;
}
shooter_.SetGoalPosition(calibration_position_, 0.0);
LOG(DEBUG, "Waiting on latch: plunger %d, latch: %d\n",
position->plunger, position->latch);
if (output) output->latch_piston = true;
if (output) output->brake_piston = false;
break;
case STATE_PREPARE_SHOT:
shooter_.SetGoalPosition(PowerToPosition(goal->shot_power), 0.0);
LOG(DEBUG, "PDIFF: adjusted_position: %.2f, pow: %.2f\n",
adjusted_position, PowerToPosition(goal->shot_power));
if (fabs(adjusted_position - PowerToPosition(goal->shot_power)) < 0.05) {
state_ = STATE_READY;
output->latch_piston = true;
output->brake_piston = true;
shooter_brake_set_time_ =
Time::Now(Time::kDefaultClock) + Time::InSeconds(0.03);
} else {
output->latch_piston = true;
output->brake_piston = false;
}
break;
case STATE_READY:
if (Time::Now() > shooter_brake_set_time_) {
shooter_loop_disable = true;
if (goal->unload_requested) {
printf("GHA\n");
state_ = STATE_UNLOAD;
} else if (fabs(adjusted_position - PowerToPosition(goal->shot_power)) >
0.05) {
printf("GHB\n");
state_ = STATE_PREPARE_SHOT;
} else if (goal->shot_requested) {
printf("GHC\n");
state_ = STATE_REQUEST_FIRE;
}
}
shooter_.SetGoalPosition(PowerToPosition(goal->shot_power), 0.0);
output->latch_piston = true;
output->brake_piston = true;
break;
case STATE_REQUEST_FIRE:
shooter_loop_disable = true;
if (position->plunger) {
prepare_fire_end_time_ =
Time::Now(Time::kDefaultClock) + Time::InMS(40.0);
apply_some_voltage = true;
state_ = STATE_PREPARE_FIRE;
} else {
state_ = STATE_REQUEST_LOAD;
}
break;
case STATE_PREPARE_FIRE:
shooter_loop_disable = true;
if (Time::Now(Time::kDefaultClock) < prepare_fire_end_time_) {
apply_some_voltage = true;
} else {
state_ = STATE_FIRE;
cycles_not_moved_ = 0;
shot_end_time_ = Time::Now(Time::kDefaultClock) + Time::InMS(500);
}
output->latch_piston = true;
output->brake_piston = true;
break;
case STATE_FIRE:
shooter_loop_disable = true;
//TODO(ben): need approamately equal
if (fabs(last_position_.position - adjusted_position) < 0.07) {
cycles_not_moved_++;
} else {
cycles_not_moved_ = 0;
}
if ((adjusted_position < 0.10 && cycles_not_moved_ > 5) ||
Time::Now(Time::kDefaultClock) > shot_end_time_) {
state_ = STATE_REQUEST_LOAD;
}
output->latch_piston = true;
output->brake_piston = true;
break;
case STATE_UNLOAD:
if (position->plunger && position->latch) {
shooter_.SetGoalPosition(0.02, 0.0);
if (adjusted_position < 0.04) {
output->latch_piston = false;
}
} else {
output->latch_piston = false;
state_ = STATE_UNLOAD_MOVE;
}
output->brake_piston = false;
break;
case STATE_UNLOAD_MOVE:
if (adjusted_position > values.shooter.upper_limit - 0.03) {
shooter_.SetGoalPosition(real_position, 0.0);
state_ = STATE_READY_UNLOAD;
} else {
shooter_.SetGoalPosition(
real_position + values.shooter.zeroing_speed * dt,
values.shooter.zeroing_speed);
}
output->latch_piston = false;
output->brake_piston = false;
break;
case STATE_READY_UNLOAD:
if (!goal->unload_requested) {
state_ = STATE_REQUEST_LOAD;
}
output->latch_piston = false;
output->brake_piston = false;
break;
}
if (apply_some_voltage) {
shooter_.Update(true);
if (output) output->voltage = 2.0;
} else if (!shooter_loop_disable) {
LOG(DEBUG, "Running the loop, goal is %f\n", shooter_.R(0, 0));
shooter_.Update(output == NULL);
if (output) output->voltage = shooter_.voltage();
} else {
shooter_.Update(true);
if (output) output->voltage = 0.0;
}
status->done =
::std::fabs(adjusted_position - PowerToPosition(goal->shot_power)) < 0.004;
}
} // namespace control_loops
} // namespace frc971