James Kuszmaul | d3f9eb2 | 2020-01-12 15:02:07 -0800 | [diff] [blame] | 1 | #include "frc971/zeroing/imu_zeroer.h" |
| 2 | |
| 3 | namespace frc971::zeroing { |
| 4 | |
James Kuszmaul | ddc6970 | 2021-03-24 21:55:03 -0700 | [diff] [blame] | 5 | namespace { |
| 6 | bool DiagStatHasFaults(const ADIS16470DiagStat &diag) { |
| 7 | return diag.clock_error() || diag.memory_failure() || diag.sensor_failure() || |
| 8 | diag.standby_mode() || diag.spi_communication_error() || |
James Kuszmaul | 6d6e130 | 2022-03-12 15:22:48 -0800 | [diff] [blame] | 9 | diag.flash_memory_update_error() || diag.data_path_overrun() || |
| 10 | diag.checksum_mismatch(); |
James Kuszmaul | ddc6970 | 2021-03-24 21:55:03 -0700 | [diff] [blame] | 11 | } |
| 12 | bool ReadingHasFaults(const IMUValues &values) { |
| 13 | if (values.has_previous_reading_diag_stat() && |
| 14 | DiagStatHasFaults(*values.previous_reading_diag_stat())) { |
| 15 | return true; |
| 16 | } |
| 17 | if (values.has_self_test_diag_stat() && |
| 18 | DiagStatHasFaults(*values.self_test_diag_stat())) { |
| 19 | return true; |
| 20 | } |
James Kuszmaul | 6d6e130 | 2022-03-12 15:22:48 -0800 | [diff] [blame] | 21 | if (values.checksum_failed()) { |
| 22 | return true; |
| 23 | } |
James Kuszmaul | ddc6970 | 2021-03-24 21:55:03 -0700 | [diff] [blame] | 24 | return false; |
| 25 | } |
| 26 | } // namespace |
| 27 | |
James Kuszmaul | 6d6e130 | 2022-03-12 15:22:48 -0800 | [diff] [blame] | 28 | ImuZeroer::ImuZeroer(FaultBehavior fault_behavior) |
| 29 | : fault_behavior_(fault_behavior) { |
James Kuszmaul | d3f9eb2 | 2020-01-12 15:02:07 -0800 | [diff] [blame] | 30 | gyro_average_.setZero(); |
| 31 | last_gyro_sample_.setZero(); |
| 32 | last_accel_sample_.setZero(); |
| 33 | } |
| 34 | |
James Kuszmaul | b1e2937 | 2020-02-11 16:55:36 -0800 | [diff] [blame] | 35 | bool ImuZeroer::Zeroed() const { |
James Kuszmaul | ddc6970 | 2021-03-24 21:55:03 -0700 | [diff] [blame] | 36 | return num_zeroes_ > kRequiredZeroPoints && !Faulted(); |
James Kuszmaul | b1e2937 | 2020-02-11 16:55:36 -0800 | [diff] [blame] | 37 | } |
James Kuszmaul | d3f9eb2 | 2020-01-12 15:02:07 -0800 | [diff] [blame] | 38 | |
James Kuszmaul | 6d6e130 | 2022-03-12 15:22:48 -0800 | [diff] [blame] | 39 | bool ImuZeroer::Faulted() const { return reading_faulted_ || zeroing_faulted_; } |
James Kuszmaul | d3f9eb2 | 2020-01-12 15:02:07 -0800 | [diff] [blame] | 40 | |
James Kuszmaul | 6d6e130 | 2022-03-12 15:22:48 -0800 | [diff] [blame] | 41 | std::optional<Eigen::Vector3d> ImuZeroer::ZeroedGyro() const { |
| 42 | return Faulted() ? std::nullopt |
| 43 | : std::make_optional<Eigen::Vector3d>(last_gyro_sample_ - |
| 44 | gyro_average_); |
James Kuszmaul | d3f9eb2 | 2020-01-12 15:02:07 -0800 | [diff] [blame] | 45 | } |
James Kuszmaul | 6d6e130 | 2022-03-12 15:22:48 -0800 | [diff] [blame] | 46 | |
| 47 | std::optional<Eigen::Vector3d> ImuZeroer::ZeroedAccel() const { |
| 48 | return Faulted() ? std::nullopt |
Lee Mracek | fddd137 | 2022-10-22 15:58:31 -0400 | [diff] [blame] | 49 | : std::make_optional<Eigen::Vector3d>(last_accel_sample_); |
James Kuszmaul | b1e2937 | 2020-02-11 16:55:36 -0800 | [diff] [blame] | 50 | } |
James Kuszmaul | 6d6e130 | 2022-03-12 15:22:48 -0800 | [diff] [blame] | 51 | |
James Kuszmaul | d3f9eb2 | 2020-01-12 15:02:07 -0800 | [diff] [blame] | 52 | Eigen::Vector3d ImuZeroer::GyroOffset() const { return gyro_average_; } |
| 53 | |
| 54 | bool ImuZeroer::GyroZeroReady() const { |
James Kuszmaul | b1e2937 | 2020-02-11 16:55:36 -0800 | [diff] [blame] | 55 | return gyro_averager_.full() && |
| 56 | gyro_averager_.GetRange() < kGyroMaxVariation && |
| 57 | (last_gyro_sample_.lpNorm<Eigen::Infinity>() < |
| 58 | kGyroMaxZeroingMagnitude); |
James Kuszmaul | d3f9eb2 | 2020-01-12 15:02:07 -0800 | [diff] [blame] | 59 | } |
| 60 | |
| 61 | bool ImuZeroer::AccelZeroReady() const { |
| 62 | return accel_averager_.full() && |
| 63 | accel_averager_.GetRange() < kAccelMaxVariation; |
| 64 | } |
| 65 | |
James Kuszmaul | b7f45bb | 2020-02-26 20:27:48 -0800 | [diff] [blame] | 66 | void ImuZeroer::InsertAndProcessMeasurement(const IMUValues &values) { |
James Kuszmaul | 6d6e130 | 2022-03-12 15:22:48 -0800 | [diff] [blame] | 67 | if (InsertMeasurement(values)) { |
| 68 | ProcessMeasurements(); |
| 69 | } |
James Kuszmaul | b7f45bb | 2020-02-26 20:27:48 -0800 | [diff] [blame] | 70 | } |
| 71 | |
James Kuszmaul | 6d6e130 | 2022-03-12 15:22:48 -0800 | [diff] [blame] | 72 | bool ImuZeroer::InsertMeasurement(const IMUValues &values) { |
James Kuszmaul | ddc6970 | 2021-03-24 21:55:03 -0700 | [diff] [blame] | 73 | if (ReadingHasFaults(values)) { |
James Kuszmaul | 6d6e130 | 2022-03-12 15:22:48 -0800 | [diff] [blame] | 74 | reading_faulted_ = true; |
| 75 | return false; |
| 76 | } |
| 77 | if (fault_behavior_ == FaultBehavior::kTemporary) { |
| 78 | reading_faulted_ = false; |
James Kuszmaul | ddc6970 | 2021-03-24 21:55:03 -0700 | [diff] [blame] | 79 | } |
James Kuszmaul | d3f9eb2 | 2020-01-12 15:02:07 -0800 | [diff] [blame] | 80 | last_gyro_sample_ << values.gyro_x(), values.gyro_y(), values.gyro_z(); |
| 81 | gyro_averager_.AddData(last_gyro_sample_); |
| 82 | last_accel_sample_ << values.accelerometer_x(), values.accelerometer_y(), |
Philipp Schrader | 790cb54 | 2023-07-05 21:06:52 -0700 | [diff] [blame] | 83 | values.accelerometer_z(); |
James Kuszmaul | d3f9eb2 | 2020-01-12 15:02:07 -0800 | [diff] [blame] | 84 | accel_averager_.AddData(last_accel_sample_); |
James Kuszmaul | 6d6e130 | 2022-03-12 15:22:48 -0800 | [diff] [blame] | 85 | return true; |
James Kuszmaul | b7f45bb | 2020-02-26 20:27:48 -0800 | [diff] [blame] | 86 | } |
| 87 | |
| 88 | void ImuZeroer::ProcessMeasurements() { |
James Kuszmaul | d3f9eb2 | 2020-01-12 15:02:07 -0800 | [diff] [blame] | 89 | if (GyroZeroReady() && AccelZeroReady()) { |
James Kuszmaul | b1e2937 | 2020-02-11 16:55:36 -0800 | [diff] [blame] | 90 | ++good_iters_; |
James Kuszmaul | b7f45bb | 2020-02-26 20:27:48 -0800 | [diff] [blame] | 91 | if (good_iters_ > kSamplesToAverage / 40) { |
James Kuszmaul | b1e2937 | 2020-02-11 16:55:36 -0800 | [diff] [blame] | 92 | const Eigen::Vector3d current_gyro_average = gyro_averager_.GetAverage(); |
| 93 | constexpr double kAverageUpdateWeight = 0.05; |
| 94 | if (num_zeroes_ > 0) { |
| 95 | gyro_average_ += |
| 96 | (current_gyro_average - gyro_average_) * kAverageUpdateWeight; |
| 97 | } else { |
| 98 | gyro_average_ = current_gyro_average; |
James Kuszmaul | d3f9eb2 | 2020-01-12 15:02:07 -0800 | [diff] [blame] | 99 | } |
James Kuszmaul | b1e2937 | 2020-02-11 16:55:36 -0800 | [diff] [blame] | 100 | if (num_zeroes_ > 0) { |
| 101 | // If we got a new zero and it is substantially different from the |
| 102 | // original zero, fault. |
| 103 | if ((current_gyro_average - gyro_average_).norm() > |
| 104 | kGyroFaultVariation) { |
James Kuszmaul | 6d6e130 | 2022-03-12 15:22:48 -0800 | [diff] [blame] | 105 | zeroing_faulted_ = true; |
| 106 | } else if (fault_behavior_ == FaultBehavior::kTemporary) { |
| 107 | zeroing_faulted_ = false; |
James Kuszmaul | b1e2937 | 2020-02-11 16:55:36 -0800 | [diff] [blame] | 108 | } |
| 109 | } |
| 110 | ++num_zeroes_; |
| 111 | gyro_averager_.Reset(); |
James Kuszmaul | d3f9eb2 | 2020-01-12 15:02:07 -0800 | [diff] [blame] | 112 | } |
James Kuszmaul | b1e2937 | 2020-02-11 16:55:36 -0800 | [diff] [blame] | 113 | } else { |
| 114 | good_iters_ = 0; |
James Kuszmaul | d3f9eb2 | 2020-01-12 15:02:07 -0800 | [diff] [blame] | 115 | } |
| 116 | } |
| 117 | |
James Kuszmaul | b1e2937 | 2020-02-11 16:55:36 -0800 | [diff] [blame] | 118 | flatbuffers::Offset<control_loops::drivetrain::ImuZeroerState> |
| 119 | ImuZeroer::PopulateStatus(flatbuffers::FlatBufferBuilder *fbb) const { |
| 120 | control_loops::drivetrain::ImuZeroerState::Builder builder(*fbb); |
| 121 | |
| 122 | builder.add_zeroed(Zeroed()); |
| 123 | builder.add_faulted(Faulted()); |
| 124 | builder.add_number_of_zeroes(num_zeroes_); |
| 125 | |
| 126 | builder.add_gyro_x_average(GyroOffset().x()); |
| 127 | builder.add_gyro_y_average(GyroOffset().y()); |
| 128 | builder.add_gyro_z_average(GyroOffset().z()); |
| 129 | |
Lee Mracek | fddd137 | 2022-10-22 15:58:31 -0400 | [diff] [blame] | 130 | builder.add_accel_x_average(accel_averager_.GetAverage()[0]); |
| 131 | builder.add_accel_y_average(accel_averager_.GetAverage()[1]); |
| 132 | builder.add_accel_z_average(accel_averager_.GetAverage()[2]); |
James Kuszmaul | 1a398fd | 2021-06-27 15:15:11 -0700 | [diff] [blame] | 133 | |
James Kuszmaul | b1e2937 | 2020-02-11 16:55:36 -0800 | [diff] [blame] | 134 | return builder.Finish(); |
| 135 | } |
| 136 | |
James Kuszmaul | d3f9eb2 | 2020-01-12 15:02:07 -0800 | [diff] [blame] | 137 | } // namespace frc971::zeroing |