blob: 615565ff9d8c9ae81bf0cd99f48354622a85dad2 [file] [log] [blame]
#ifndef Y2017_CONTROL_LOOPS_SUPERSTRUCTURE_COLUMN_COLUMN_H_
#define Y2017_CONTROL_LOOPS_SUPERSTRUCTURE_COLUMN_COLUMN_H_
#include <array>
#include <chrono>
#include <memory>
#include <utility>
#include "Eigen/Dense"
#include "frc971/constants.h"
#include "frc971/control_loops/profiled_subsystem.h"
#include "frc971/control_loops/state_feedback_loop.h"
#include "y2017/constants.h"
#include "y2017/control_loops/superstructure/column/column_zeroing.h"
#include "y2017/control_loops/superstructure/intake/intake.h"
#include "y2017/control_loops/superstructure/superstructure_position_generated.h"
#include "y2017/control_loops/superstructure/superstructure_status_generated.h"
#include "y2017/control_loops/superstructure/vision_time_adjuster.h"
#include "y2017/vision/vision_generated.h"
namespace y2017 {
namespace control_loops {
namespace superstructure {
namespace column {
class ColumnProfiledSubsystem
: public ::frc971::control_loops::ProfiledSubsystem<
6, 1, ColumnZeroingEstimator, 2, 2> {
public:
ColumnProfiledSubsystem(
::std::unique_ptr<
::frc971::control_loops::SimpleCappedStateFeedbackLoop<6, 2, 2>>
loop,
const ::y2017::constants::Values::Column &zeroing_constants,
const ::frc971::constants::Range &range, double default_angular_velocity,
double default_angular_acceleration);
// Updates our estimator with the latest position.
void Correct(const ColumnPosition &position);
// Runs the controller and profile generator for a cycle.
void Update(bool disabled);
// Fills out the ProfiledJointStatus structure with the current state.
void PopulateTurretStatus(
TurretProfiledSubsystemStatus::Builder *status_builder,
flatbuffers::Offset<ColumnZeroingEstimator::State>
estimator_state_offset);
// Forces the current goal to the provided goal, bypassing the profiler.
void ForceGoal(double goal_velocity, double goal);
// Sets the unprofiled goal. The profiler will generate a profile to go to
// this goal.
void set_indexer_unprofiled_goal(double goal_velocity);
void set_turret_unprofiled_goal(double unprofiled_goal);
void set_unprofiled_goal(double goal_velocity, double unprofiled_goal);
// Limits our profiles to a max velocity and acceleration for proper motion.
void AdjustProfile(const ::frc971::ProfileParameters *profile_parameters);
void AdjustProfile(double max_angular_velocity,
double max_angular_acceleration);
// Returns true if we have exceeded any hard limits.
bool CheckHardLimits();
// Returns the requested voltage.
double indexer_voltage() const { return loop_->U(0, 0); }
double uncapped_indexer_voltage() const { return loop_->U_uncapped(0, 0); }
double turret_voltage() const { return loop_->U(1, 0); }
// Returns the current Y.
const ::Eigen::Matrix<double, 2, 1> Y() const { return Y_; }
double Y(int i, int j) const { return Y_(i, j); }
// Returns the current indexer position.
double indexer_position() const { return Y_(0, 0); }
bool saturated() const { return saturated_; }
// Returns the current turret position.
double turret_position() const { return Y_(1, 0) + Y_(0, 0); }
// For testing:
// Triggers an estimator error.
void TriggerEstimatorError() { estimators_[0].TriggerError(); }
const ::frc971::constants::Range &range() const { return range_; }
bool IsIndexerStuck() const;
double IndexerStuckVoltage() const;
void PartialIndexerReset();
void PartialTurretReset();
void PopulateIndexerStatus(IndexerStatus::Builder *status_builder);
void AddOffset(double indexer_offset_delta, double turret_offset_delta);
protected:
// Limits the provided goal to the soft limits. Prints "name" when it fails
// to aid debugging.
virtual void CapGoal(const char *name, Eigen::Matrix<double, 6, 1> *goal);
private:
void UpdateOffset(double indexer_offset, double turret_offset);
::std::unique_ptr<StateFeedbackLoop<6, 2, 2>> stuck_indexer_detector_;
// History array for calculating a filtered angular velocity.
static constexpr int kHistoryLength = 5;
::std::array<double, kHistoryLength> indexer_history_;
ptrdiff_t indexer_history_position_ = 0;
double indexer_error_ = 0.0;
double indexer_dt_velocity_ = 0.0;
double indexer_last_position_ = 0.0;
double indexer_average_angular_velocity_ = 0.0;
double indexer_position_error_ = 0.0;
bool indexer_ready_ = false;
bool saturated_ = false;
Eigen::Matrix<double, 6, 1> X_hat_current_;
Eigen::Matrix<double, 6, 1> stuck_indexer_X_hat_current_;
aos::util::TrapezoidProfile profile_;
// Current measurement.
Eigen::Matrix<double, 2, 1> Y_;
// Current offset. Y_ = offset_ + raw_sensor;
Eigen::Matrix<double, 2, 1> offset_;
const ::frc971::constants::Range range_;
const double default_velocity_;
const double default_acceleration_;
double turret_last_position_ = 0;
};
class Column {
public:
Column(::aos::EventLoop *event_loop);
double goal(int row, int col) const {
return profiled_subsystem_.goal(row, col);
}
double turret_position() const {
return profiled_subsystem_.turret_position();
}
void set_freeze(bool freeze) { freeze_ = freeze; }
// The zeroing and operating voltages.
static constexpr double kZeroingVoltage = 5.0;
static constexpr double kOperatingVoltage = 12.0;
static constexpr double kIntakeZeroingMinDistance = 0.08;
static constexpr double kIntakeTolerance = 0.005;
static constexpr double kStuckZeroingTrackingError = 0.02;
static constexpr double kTurretMin = -0.1;
static constexpr double kTurretMax = M_PI / 2.0 + 0.1;
std::pair<flatbuffers::Offset<IndexerStatus>,
flatbuffers::Offset<TurretProfiledSubsystemStatus>>
Iterate(::aos::monotonic_clock::time_point monotonic_now,
const IndexerGoalT *unsafe_indexer_goal,
const TurretGoal *unsafe_turret_goal, const ColumnPosition *position,
const vision::VisionStatus *vision_status, double *indexer_output,
double *turret_output, flatbuffers::FlatBufferBuilder *fbb,
// IndexerStatus *indexer_status,
// TurretProfiledSubsystemStatus *turret_status,
intake::Intake *intake);
void Reset();
enum class State : int32_t {
UNINITIALIZED = 0,
ZEROING_UNINITIALIZED = 1,
ZEROING_POSITIVE = 2,
ZEROING_NEGATIVE = 3,
RUNNING = 4,
ESTOP = 5,
};
enum class IndexerState : int32_t {
// The system is running correctly, no stuck condition detected.
RUNNING = 0,
// The system is reversing to unjam.
REVERSING = 1
};
State state() const { return state_; }
IndexerState indexer_state() const { return indexer_state_; }
private:
State state_ = State::UNINITIALIZED;
IndexerState indexer_state_ = IndexerState::RUNNING;
bool freeze_ = false;
VisionTimeAdjuster vision_time_adjuster_;
// The last time that we transitioned from RUNNING to REVERSING or the
// reverse. Used to implement the timeouts.
::aos::monotonic_clock::time_point last_transition_time_ =
::aos::monotonic_clock::min_time;
ColumnProfiledSubsystem profiled_subsystem_;
const double vision_error_;
};
} // namespace column
} // namespace superstructure
} // namespace control_loops
} // namespace y2017
#endif // Y2017_CONTROL_LOOPS_SUPERSTRUCTURE_COLUMN_COLUMN_H_