blob: f0d81cb1eac61045fb922d264255544385ab5665 [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"
James Kuszmaul5bc6fc92019-03-01 21:50:06 -08006#include "frc971/control_loops/pose.h"
James Kuszmaul3431d622019-02-17 17:07:44 -08007
8namespace frc971 {
9namespace control_loops {
10namespace drivetrain {
11
James Kuszmaul5bc6fc92019-03-01 21:50:06 -080012// An interface for target selection. This provides an object that will take in
13// state updates and then determine what poes we should be driving to.
14class TargetSelectorInterface {
15 public:
16 // Take the state as [x, y, theta, left_vel, right_vel]
17 // If unable to determine what target to go for, returns false. If a viable
18 // target is selected, then returns true and sets target_pose.
19 // TODO(james): Some implementations may also want a drivetrain goal so that
20 // driver intent can be divined more directly.
21 virtual bool UpdateSelection(const ::Eigen::Matrix<double, 5, 1> &state) = 0;
22 // Gets the current target pose. Should only be called if UpdateSelection has
23 // returned true.
24 virtual TypedPose<double> TargetPose() const = 0;
25};
26
James Kuszmaul3431d622019-02-17 17:07:44 -080027// Defines an interface for classes that provide field-global localization.
28class LocalizerInterface {
29 public:
30 // Perform a single step of the filter, using the information that is
31 // available on every drivetrain iteration.
32 // The user should pass in the U that the real system experienced from the
33 // previous timestep until now; internally, any filters will first perform a
34 // prediction step to get the estimate at time now, and then will apply
35 // corrections based on the encoder/gyro/accelerometer values from time now.
36 // TODO(james): Consider letting implementations subscribe to the sensor
37 // values themselves, and then only passing in U. This requires more
38 // coordination on timing, however.
39 virtual void Update(const ::Eigen::Matrix<double, 2, 1> &U,
40 ::aos::monotonic_clock::time_point now,
41 double left_encoder, double right_encoder,
42 double gyro_rate, double longitudinal_accelerometer) = 0;
James Kuszmaulef428a02019-03-02 22:19:41 -080043 // Reset the absolute position of the estimator.
44 virtual void ResetPosition(double x, double y, double theta) = 0;
James Kuszmaul3431d622019-02-17 17:07:44 -080045 // There are several subtly different norms floating around for state
46 // matrices. In order to avoid that mess, we jus tprovide direct accessors for
47 // the values that most people care about.
48 virtual double x() const = 0;
49 virtual double y() const = 0;
50 virtual double theta() const = 0;
51 virtual double left_velocity() const = 0;
52 virtual double right_velocity() const = 0;
53 virtual double left_voltage_error() const = 0;
54 virtual double right_voltage_error() const = 0;
James Kuszmaul5bc6fc92019-03-01 21:50:06 -080055 virtual TargetSelectorInterface *target_selector() = 0;
56};
57
58// A target selector, primarily for testing purposes, that just lets a user
59// manually set the target selector state.
60class TrivialTargetSelector : public TargetSelectorInterface {
61 public:
62 bool UpdateSelection(const ::Eigen::Matrix<double, 5, 1> &) override {
63 return has_target_;
64 }
65 TypedPose<double> TargetPose() const override { return pose_; }
66
67 void set_pose(const TypedPose<double> &pose) { pose_ = pose; }
68 void set_has_target(bool has_target) { has_target_ = has_target; }
69 bool has_target() const { return has_target_; }
70
71 private:
72 bool has_target_ = true;
73 TypedPose<double> pose_;
James Kuszmaul3431d622019-02-17 17:07:44 -080074};
75
76// Uses the generic HybridEkf implementation to provide a basic field estimator.
77// This provides no method for using cameras or the such to get global
78// measurements and just assumes that you can dead-reckon perfectly.
79class DeadReckonEkf : public LocalizerInterface {
80 typedef HybridEkf<double> Ekf;
81 typedef typename Ekf::StateIdx StateIdx;
82 public:
83 DeadReckonEkf(const DrivetrainConfig<double> &dt_config) : ekf_(dt_config) {
84 ekf_.ResetInitialState(::aos::monotonic_clock::now(), Ekf::State::Zero(),
85 ekf_.P());
James Kuszmaul5bc6fc92019-03-01 21:50:06 -080086 target_selector_.set_has_target(false);
James Kuszmaul3431d622019-02-17 17:07:44 -080087 }
88
89 void Update(const ::Eigen::Matrix<double, 2, 1> &U,
90 ::aos::monotonic_clock::time_point now,
91 double left_encoder, double right_encoder,
92 double gyro_rate,
93 double /*longitudinal_accelerometer*/) override {
94 ekf_.UpdateEncodersAndGyro(left_encoder, right_encoder, gyro_rate, U, now);
95 }
96
James Kuszmaulef428a02019-03-02 22:19:41 -080097 void ResetPosition(double x, double y, double theta) override {
James Kuszmaulfedc4612019-03-10 11:24:51 -070098 const double left_encoder = ekf_.X_hat(StateIdx::kLeftEncoder);
99 const double right_encoder = ekf_.X_hat(StateIdx::kRightEncoder);
James Kuszmaulef428a02019-03-02 22:19:41 -0800100 ekf_.ResetInitialState(
101 ::aos::monotonic_clock::now(),
James Kuszmaulfedc4612019-03-10 11:24:51 -0700102 (Ekf::State() << x, y, theta, left_encoder, 0, right_encoder, 0)
103 .finished(),
James Kuszmaulef428a02019-03-02 22:19:41 -0800104 ekf_.P());
105 };
106
James Kuszmaul3431d622019-02-17 17:07:44 -0800107 double x() const override { return ekf_.X_hat(StateIdx::kX); }
108 double y() const override { return ekf_.X_hat(StateIdx::kY); }
109 double theta() const override { return ekf_.X_hat(StateIdx::kTheta); }
110 double left_velocity() const override {
111 return ekf_.X_hat(StateIdx::kLeftVelocity);
112 }
113 double right_velocity() const override {
114 return ekf_.X_hat(StateIdx::kRightVelocity);
115 }
James Kuszmaulfedc4612019-03-10 11:24:51 -0700116 double left_voltage_error() const override { return 0.0; }
117 double right_voltage_error() const override { return 0.0; }
James Kuszmaul3431d622019-02-17 17:07:44 -0800118
James Kuszmaul5bc6fc92019-03-01 21:50:06 -0800119 TrivialTargetSelector *target_selector() override {
120 return &target_selector_;
121 }
122
James Kuszmaul3431d622019-02-17 17:07:44 -0800123 private:
124 Ekf ekf_;
James Kuszmaul5bc6fc92019-03-01 21:50:06 -0800125 TrivialTargetSelector target_selector_;
James Kuszmaul3431d622019-02-17 17:07:44 -0800126};
127
128} // namespace drivetrain
129} // namespace control_loops
130} // namespace frc971
131
132#endif // FRC971_CONTROL_LOOPS_DRIVETRAIN_FIELD_ESTIMATOR_H_