blob: 5d5b58d51d90271f19c036d6b0dbca61275f7847 [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;
43 // There are several subtly different norms floating around for state
44 // matrices. In order to avoid that mess, we jus tprovide direct accessors for
45 // the values that most people care about.
46 virtual double x() const = 0;
47 virtual double y() const = 0;
48 virtual double theta() const = 0;
49 virtual double left_velocity() const = 0;
50 virtual double right_velocity() const = 0;
51 virtual double left_voltage_error() const = 0;
52 virtual double right_voltage_error() const = 0;
James Kuszmaul5bc6fc92019-03-01 21:50:06 -080053 virtual TargetSelectorInterface *target_selector() = 0;
54};
55
56// A target selector, primarily for testing purposes, that just lets a user
57// manually set the target selector state.
58class TrivialTargetSelector : public TargetSelectorInterface {
59 public:
60 bool UpdateSelection(const ::Eigen::Matrix<double, 5, 1> &) override {
61 return has_target_;
62 }
63 TypedPose<double> TargetPose() const override { return pose_; }
64
65 void set_pose(const TypedPose<double> &pose) { pose_ = pose; }
66 void set_has_target(bool has_target) { has_target_ = has_target; }
67 bool has_target() const { return has_target_; }
68
69 private:
70 bool has_target_ = true;
71 TypedPose<double> pose_;
James Kuszmaul3431d622019-02-17 17:07:44 -080072};
73
74// Uses the generic HybridEkf implementation to provide a basic field estimator.
75// This provides no method for using cameras or the such to get global
76// measurements and just assumes that you can dead-reckon perfectly.
77class DeadReckonEkf : public LocalizerInterface {
78 typedef HybridEkf<double> Ekf;
79 typedef typename Ekf::StateIdx StateIdx;
80 public:
81 DeadReckonEkf(const DrivetrainConfig<double> &dt_config) : ekf_(dt_config) {
82 ekf_.ResetInitialState(::aos::monotonic_clock::now(), Ekf::State::Zero(),
83 ekf_.P());
James Kuszmaul5bc6fc92019-03-01 21:50:06 -080084 target_selector_.set_has_target(false);
James Kuszmaul3431d622019-02-17 17:07:44 -080085 }
86
87 void Update(const ::Eigen::Matrix<double, 2, 1> &U,
88 ::aos::monotonic_clock::time_point now,
89 double left_encoder, double right_encoder,
90 double gyro_rate,
91 double /*longitudinal_accelerometer*/) override {
92 ekf_.UpdateEncodersAndGyro(left_encoder, right_encoder, gyro_rate, U, now);
93 }
94
95 double x() const override { return ekf_.X_hat(StateIdx::kX); }
96 double y() const override { return ekf_.X_hat(StateIdx::kY); }
97 double theta() const override { return ekf_.X_hat(StateIdx::kTheta); }
98 double left_velocity() const override {
99 return ekf_.X_hat(StateIdx::kLeftVelocity);
100 }
101 double right_velocity() const override {
102 return ekf_.X_hat(StateIdx::kRightVelocity);
103 }
104 double left_voltage_error() const override {
105 return ekf_.X_hat(StateIdx::kLeftVoltageError);
106 }
107 double right_voltage_error() const override {
108 return ekf_.X_hat(StateIdx::kRightVoltageError);
109 }
110
James Kuszmaul5bc6fc92019-03-01 21:50:06 -0800111 TrivialTargetSelector *target_selector() override {
112 return &target_selector_;
113 }
114
James Kuszmaul3431d622019-02-17 17:07:44 -0800115 private:
116 Ekf ekf_;
James Kuszmaul5bc6fc92019-03-01 21:50:06 -0800117 TrivialTargetSelector target_selector_;
James Kuszmaul3431d622019-02-17 17:07:44 -0800118};
119
120} // namespace drivetrain
121} // namespace control_loops
122} // namespace frc971
123
124#endif // FRC971_CONTROL_LOOPS_DRIVETRAIN_FIELD_ESTIMATOR_H_