blob: e0746682196ebf686e129d828535dce87709bfec [file] [log] [blame]
#include "frc971/zeroing/hall_effect_and_position.h"
#include <algorithm>
#include <cmath>
#include <limits>
#include "glog/logging.h"
namespace frc971 {
namespace zeroing {
HallEffectAndPositionZeroingEstimator::HallEffectAndPositionZeroingEstimator(
const ZeroingConstants &constants)
: constants_(constants) {
Reset();
}
void HallEffectAndPositionZeroingEstimator::Reset() {
offset_ = 0.0;
min_low_position_ = ::std::numeric_limits<double>::max();
max_low_position_ = ::std::numeric_limits<double>::lowest();
zeroed_ = false;
initialized_ = false;
last_used_posedge_count_ = 0;
cycles_high_ = 0;
high_long_enough_ = false;
first_start_pos_ = 0.0;
error_ = false;
current_ = 0.0;
first_start_pos_ = 0.0;
}
void HallEffectAndPositionZeroingEstimator::TriggerError() {
if (!error_) {
VLOG(1) << "Manually triggered zeroing error.\n";
error_ = true;
}
}
void HallEffectAndPositionZeroingEstimator::StoreEncoderMaxAndMin(
const HallEffectAndPosition &info) {
// If we have a new posedge.
if (!info.current()) {
if (last_hall_) {
min_low_position_ = max_low_position_ = info.encoder();
} else {
min_low_position_ = ::std::min(min_low_position_, info.encoder());
max_low_position_ = ::std::max(max_low_position_, info.encoder());
}
}
last_hall_ = info.current();
}
void HallEffectAndPositionZeroingEstimator::UpdateEstimate(
const HallEffectAndPosition &info) {
// We want to make sure that we encounter at least one posedge while zeroing.
// So we take the posedge count from the first sample after reset and wait for
// that count to change and for the hall effect to stay high before we
// consider ourselves zeroed.
if (!initialized_) {
last_used_posedge_count_ = info.posedge_count();
initialized_ = true;
last_hall_ = info.current();
}
StoreEncoderMaxAndMin(info);
if (info.current()) {
cycles_high_++;
} else {
cycles_high_ = 0;
last_used_posedge_count_ = info.posedge_count();
}
high_long_enough_ = cycles_high_ >= constants_.hall_trigger_zeroing_length;
bool moving_backward = false;
if (constants_.zeroing_move_direction) {
moving_backward = info.encoder() > min_low_position_;
} else {
moving_backward = info.encoder() < max_low_position_;
}
// If there are no posedges to use or we don't have enough samples yet to
// have a well-filtered starting position then we use the filtered value as
// our best guess.
if (last_used_posedge_count_ != info.posedge_count() && high_long_enough_ &&
moving_backward) {
// Note the offset and the current posedge count so that we only run this
// logic once per posedge. That should be more resilient to corrupted
// intermediate data.
offset_ = -info.posedge_value();
if (constants_.zeroing_move_direction) {
offset_ += constants_.lower_hall_position;
} else {
offset_ += constants_.upper_hall_position;
}
last_used_posedge_count_ = info.posedge_count();
// Save the first starting position.
if (!zeroed_) {
first_start_pos_ = offset_;
VLOG(2) << "latching start position" << first_start_pos_;
}
// Now that we have an accurate starting position we can consider ourselves
// zeroed.
zeroed_ = true;
}
position_ = info.encoder() - offset_;
}
flatbuffers::Offset<HallEffectAndPositionZeroingEstimator::State>
HallEffectAndPositionZeroingEstimator::GetEstimatorState(
flatbuffers::FlatBufferBuilder *fbb) const {
State::Builder builder(*fbb);
builder.add_error(error_);
builder.add_zeroed(zeroed_);
builder.add_encoder(position_);
builder.add_high_long_enough(high_long_enough_);
builder.add_offset(offset_);
return builder.Finish();
}
} // namespace zeroing
} // namespace frc971