blob: 4da8b57b08419e31bf8d2f70a0bd23c6b273ea8d [file] [log] [blame]
James Kuszmaul3431d622019-02-17 17:07:44 -08001#ifndef FRC971_CONTROL_LOOPS_DRIVETRAIN_FIELD_ESTIMATOR_H_
2#define FRC971_CONTROL_LOOPS_DRIVETRAIN_FIELD_ESTIMATOR_H_
3
4#include "frc971/control_loops/drivetrain/drivetrain_config.h"
5#include "frc971/control_loops/drivetrain/hybrid_ekf.h"
6
7namespace frc971 {
8namespace control_loops {
9namespace drivetrain {
10
11// Defines an interface for classes that provide field-global localization.
12class LocalizerInterface {
13 public:
14 // Perform a single step of the filter, using the information that is
15 // available on every drivetrain iteration.
16 // The user should pass in the U that the real system experienced from the
17 // previous timestep until now; internally, any filters will first perform a
18 // prediction step to get the estimate at time now, and then will apply
19 // corrections based on the encoder/gyro/accelerometer values from time now.
20 // TODO(james): Consider letting implementations subscribe to the sensor
21 // values themselves, and then only passing in U. This requires more
22 // coordination on timing, however.
23 virtual void Update(const ::Eigen::Matrix<double, 2, 1> &U,
24 ::aos::monotonic_clock::time_point now,
25 double left_encoder, double right_encoder,
26 double gyro_rate, double longitudinal_accelerometer) = 0;
27 // There are several subtly different norms floating around for state
28 // matrices. In order to avoid that mess, we jus tprovide direct accessors for
29 // the values that most people care about.
30 virtual double x() const = 0;
31 virtual double y() const = 0;
32 virtual double theta() const = 0;
33 virtual double left_velocity() const = 0;
34 virtual double right_velocity() const = 0;
35 virtual double left_voltage_error() const = 0;
36 virtual double right_voltage_error() const = 0;
37};
38
39// Uses the generic HybridEkf implementation to provide a basic field estimator.
40// This provides no method for using cameras or the such to get global
41// measurements and just assumes that you can dead-reckon perfectly.
42class DeadReckonEkf : public LocalizerInterface {
43 typedef HybridEkf<double> Ekf;
44 typedef typename Ekf::StateIdx StateIdx;
45 public:
46 DeadReckonEkf(const DrivetrainConfig<double> &dt_config) : ekf_(dt_config) {
47 ekf_.ResetInitialState(::aos::monotonic_clock::now(), Ekf::State::Zero(),
48 ekf_.P());
49 }
50
51 void Update(const ::Eigen::Matrix<double, 2, 1> &U,
52 ::aos::monotonic_clock::time_point now,
53 double left_encoder, double right_encoder,
54 double gyro_rate,
55 double /*longitudinal_accelerometer*/) override {
56 ekf_.UpdateEncodersAndGyro(left_encoder, right_encoder, gyro_rate, U, now);
57 }
58
59 double x() const override { return ekf_.X_hat(StateIdx::kX); }
60 double y() const override { return ekf_.X_hat(StateIdx::kY); }
61 double theta() const override { return ekf_.X_hat(StateIdx::kTheta); }
62 double left_velocity() const override {
63 return ekf_.X_hat(StateIdx::kLeftVelocity);
64 }
65 double right_velocity() const override {
66 return ekf_.X_hat(StateIdx::kRightVelocity);
67 }
68 double left_voltage_error() const override {
69 return ekf_.X_hat(StateIdx::kLeftVoltageError);
70 }
71 double right_voltage_error() const override {
72 return ekf_.X_hat(StateIdx::kRightVoltageError);
73 }
74
75 private:
76 Ekf ekf_;
77};
78
79} // namespace drivetrain
80} // namespace control_loops
81} // namespace frc971
82
83#endif // FRC971_CONTROL_LOOPS_DRIVETRAIN_FIELD_ESTIMATOR_H_