blob: 23a978ceeb00459b2f22cdbf4dca76229fe85a79 [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.
James Kuszmaulc4bd1612019-03-10 11:35:06 -070019 // command_speed is the goal speed of the current drivetrain, generally
20 // generated from the throttle and meant to signify driver intent.
James Kuszmaul5bc6fc92019-03-01 21:50:06 -080021 // TODO(james): Some implementations may also want a drivetrain goal so that
22 // driver intent can be divined more directly.
James Kuszmaulc4bd1612019-03-10 11:35:06 -070023 virtual bool UpdateSelection(const ::Eigen::Matrix<double, 5, 1> &state,
24 double command_speed) = 0;
James Kuszmaul5bc6fc92019-03-01 21:50:06 -080025 // Gets the current target pose. Should only be called if UpdateSelection has
26 // returned true.
27 virtual TypedPose<double> TargetPose() const = 0;
James Kuszmaule093f512019-03-20 06:14:05 -070028 // The "radius" of the target--for y2019, we wanted to drive in so that a disc
29 // with radius r would hit the plane of the target at an offset of exactly r
30 // from the TargetPose--this is distinct from wanting the center of the
31 // robot to project straight onto the center of the target.
32 virtual double TargetRadius() const = 0;
James Kuszmaul5bc6fc92019-03-01 21:50:06 -080033};
34
James Kuszmaul3431d622019-02-17 17:07:44 -080035// Defines an interface for classes that provide field-global localization.
36class LocalizerInterface {
37 public:
38 // Perform a single step of the filter, using the information that is
39 // available on every drivetrain iteration.
40 // The user should pass in the U that the real system experienced from the
41 // previous timestep until now; internally, any filters will first perform a
42 // prediction step to get the estimate at time now, and then will apply
43 // corrections based on the encoder/gyro/accelerometer values from time now.
44 // TODO(james): Consider letting implementations subscribe to the sensor
45 // values themselves, and then only passing in U. This requires more
46 // coordination on timing, however.
47 virtual void Update(const ::Eigen::Matrix<double, 2, 1> &U,
48 ::aos::monotonic_clock::time_point now,
49 double left_encoder, double right_encoder,
50 double gyro_rate, double longitudinal_accelerometer) = 0;
James Kuszmaulef428a02019-03-02 22:19:41 -080051 // Reset the absolute position of the estimator.
James Kuszmaul074429e2019-03-23 16:01:49 -070052 virtual void ResetPosition(::aos::monotonic_clock::time_point t, double x,
James Kuszmaul518640d2019-04-13 15:50:50 -070053 double y, double theta, double theta_uncertainty,
54 bool reset_theta) = 0;
James Kuszmaul3431d622019-02-17 17:07:44 -080055 // There are several subtly different norms floating around for state
56 // matrices. In order to avoid that mess, we jus tprovide direct accessors for
57 // the values that most people care about.
58 virtual double x() const = 0;
59 virtual double y() const = 0;
60 virtual double theta() const = 0;
61 virtual double left_velocity() const = 0;
62 virtual double right_velocity() const = 0;
James Kuszmaul074429e2019-03-23 16:01:49 -070063 virtual double left_encoder() const = 0;
64 virtual double right_encoder() const = 0;
James Kuszmaul3431d622019-02-17 17:07:44 -080065 virtual double left_voltage_error() const = 0;
66 virtual double right_voltage_error() const = 0;
James Kuszmaul5bc6fc92019-03-01 21:50:06 -080067 virtual TargetSelectorInterface *target_selector() = 0;
68};
69
70// A target selector, primarily for testing purposes, that just lets a user
71// manually set the target selector state.
72class TrivialTargetSelector : public TargetSelectorInterface {
73 public:
James Kuszmaulc4bd1612019-03-10 11:35:06 -070074 bool UpdateSelection(const ::Eigen::Matrix<double, 5, 1> &, double) override {
James Kuszmaul5bc6fc92019-03-01 21:50:06 -080075 return has_target_;
76 }
77 TypedPose<double> TargetPose() const override { return pose_; }
James Kuszmaule093f512019-03-20 06:14:05 -070078 double TargetRadius() const override { return target_radius_; }
James Kuszmaul5bc6fc92019-03-01 21:50:06 -080079
80 void set_pose(const TypedPose<double> &pose) { pose_ = pose; }
James Kuszmaule093f512019-03-20 06:14:05 -070081 void set_target_radius(double radius) { target_radius_ = radius; }
James Kuszmaul5bc6fc92019-03-01 21:50:06 -080082 void set_has_target(bool has_target) { has_target_ = has_target; }
83 bool has_target() const { return has_target_; }
84
85 private:
86 bool has_target_ = true;
87 TypedPose<double> pose_;
James Kuszmaule093f512019-03-20 06:14:05 -070088 double target_radius_ = 0.0;
James Kuszmaul3431d622019-02-17 17:07:44 -080089};
90
91// Uses the generic HybridEkf implementation to provide a basic field estimator.
92// This provides no method for using cameras or the such to get global
93// measurements and just assumes that you can dead-reckon perfectly.
94class DeadReckonEkf : public LocalizerInterface {
95 typedef HybridEkf<double> Ekf;
96 typedef typename Ekf::StateIdx StateIdx;
97 public:
98 DeadReckonEkf(const DrivetrainConfig<double> &dt_config) : ekf_(dt_config) {
99 ekf_.ResetInitialState(::aos::monotonic_clock::now(), Ekf::State::Zero(),
100 ekf_.P());
James Kuszmaul5bc6fc92019-03-01 21:50:06 -0800101 target_selector_.set_has_target(false);
James Kuszmaul3431d622019-02-17 17:07:44 -0800102 }
103
104 void Update(const ::Eigen::Matrix<double, 2, 1> &U,
105 ::aos::monotonic_clock::time_point now,
106 double left_encoder, double right_encoder,
107 double gyro_rate,
108 double /*longitudinal_accelerometer*/) override {
109 ekf_.UpdateEncodersAndGyro(left_encoder, right_encoder, gyro_rate, U, now);
110 }
111
James Kuszmaul074429e2019-03-23 16:01:49 -0700112 void ResetPosition(::aos::monotonic_clock::time_point t, double x, double y,
James Kuszmaul518640d2019-04-13 15:50:50 -0700113 double theta, double /*theta_override*/,
114 bool /*reset_theta*/) override {
James Kuszmaulfedc4612019-03-10 11:24:51 -0700115 const double left_encoder = ekf_.X_hat(StateIdx::kLeftEncoder);
116 const double right_encoder = ekf_.X_hat(StateIdx::kRightEncoder);
James Kuszmaul074429e2019-03-23 16:01:49 -0700117 ekf_.ResetInitialState(t, (Ekf::State() << x, y, theta, left_encoder, 0,
118 right_encoder, 0, 0, 0, 0).finished(),
119 ekf_.P());
James Kuszmaulef428a02019-03-02 22:19:41 -0800120 };
121
James Kuszmaul3431d622019-02-17 17:07:44 -0800122 double x() const override { return ekf_.X_hat(StateIdx::kX); }
123 double y() const override { return ekf_.X_hat(StateIdx::kY); }
124 double theta() const override { return ekf_.X_hat(StateIdx::kTheta); }
James Kuszmaul074429e2019-03-23 16:01:49 -0700125 double left_encoder() const override {
126 return ekf_.X_hat(StateIdx::kLeftEncoder);
127 }
128 double right_encoder() const override {
129 return ekf_.X_hat(StateIdx::kRightEncoder);
130 }
James Kuszmaul3431d622019-02-17 17:07:44 -0800131 double left_velocity() const override {
132 return ekf_.X_hat(StateIdx::kLeftVelocity);
133 }
134 double right_velocity() const override {
135 return ekf_.X_hat(StateIdx::kRightVelocity);
136 }
James Kuszmaul074429e2019-03-23 16:01:49 -0700137 double left_voltage_error() const override {
138 return ekf_.X_hat(StateIdx::kLeftVoltageError);
139 }
140 double right_voltage_error() const override {
141 return ekf_.X_hat(StateIdx::kRightVoltageError);
142 }
James Kuszmaul3431d622019-02-17 17:07:44 -0800143
James Kuszmaul5bc6fc92019-03-01 21:50:06 -0800144 TrivialTargetSelector *target_selector() override {
145 return &target_selector_;
146 }
147
James Kuszmaul3431d622019-02-17 17:07:44 -0800148 private:
149 Ekf ekf_;
James Kuszmaul5bc6fc92019-03-01 21:50:06 -0800150 TrivialTargetSelector target_selector_;
James Kuszmaul3431d622019-02-17 17:07:44 -0800151};
152
153} // namespace drivetrain
154} // namespace control_loops
155} // namespace frc971
156
157#endif // FRC971_CONTROL_LOOPS_DRIVETRAIN_FIELD_ESTIMATOR_H_