blob: 986680376dd5a65b52ac408441dc524c526cdb62 [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,
53 double y, double theta) = 0;
James Kuszmaul3431d622019-02-17 17:07:44 -080054 // There are several subtly different norms floating around for state
55 // matrices. In order to avoid that mess, we jus tprovide direct accessors for
56 // the values that most people care about.
57 virtual double x() const = 0;
58 virtual double y() const = 0;
59 virtual double theta() const = 0;
60 virtual double left_velocity() const = 0;
61 virtual double right_velocity() const = 0;
James Kuszmaul074429e2019-03-23 16:01:49 -070062 virtual double left_encoder() const = 0;
63 virtual double right_encoder() const = 0;
James Kuszmaul3431d622019-02-17 17:07:44 -080064 virtual double left_voltage_error() const = 0;
65 virtual double right_voltage_error() const = 0;
James Kuszmaul5bc6fc92019-03-01 21:50:06 -080066 virtual TargetSelectorInterface *target_selector() = 0;
67};
68
69// A target selector, primarily for testing purposes, that just lets a user
70// manually set the target selector state.
71class TrivialTargetSelector : public TargetSelectorInterface {
72 public:
James Kuszmaulc4bd1612019-03-10 11:35:06 -070073 bool UpdateSelection(const ::Eigen::Matrix<double, 5, 1> &, double) override {
James Kuszmaul5bc6fc92019-03-01 21:50:06 -080074 return has_target_;
75 }
76 TypedPose<double> TargetPose() const override { return pose_; }
James Kuszmaule093f512019-03-20 06:14:05 -070077 double TargetRadius() const override { return target_radius_; }
James Kuszmaul5bc6fc92019-03-01 21:50:06 -080078
79 void set_pose(const TypedPose<double> &pose) { pose_ = pose; }
James Kuszmaule093f512019-03-20 06:14:05 -070080 void set_target_radius(double radius) { target_radius_ = radius; }
James Kuszmaul5bc6fc92019-03-01 21:50:06 -080081 void set_has_target(bool has_target) { has_target_ = has_target; }
82 bool has_target() const { return has_target_; }
83
84 private:
85 bool has_target_ = true;
86 TypedPose<double> pose_;
James Kuszmaule093f512019-03-20 06:14:05 -070087 double target_radius_ = 0.0;
James Kuszmaul3431d622019-02-17 17:07:44 -080088};
89
90// Uses the generic HybridEkf implementation to provide a basic field estimator.
91// This provides no method for using cameras or the such to get global
92// measurements and just assumes that you can dead-reckon perfectly.
93class DeadReckonEkf : public LocalizerInterface {
94 typedef HybridEkf<double> Ekf;
95 typedef typename Ekf::StateIdx StateIdx;
96 public:
97 DeadReckonEkf(const DrivetrainConfig<double> &dt_config) : ekf_(dt_config) {
98 ekf_.ResetInitialState(::aos::monotonic_clock::now(), Ekf::State::Zero(),
99 ekf_.P());
James Kuszmaul5bc6fc92019-03-01 21:50:06 -0800100 target_selector_.set_has_target(false);
James Kuszmaul3431d622019-02-17 17:07:44 -0800101 }
102
103 void Update(const ::Eigen::Matrix<double, 2, 1> &U,
104 ::aos::monotonic_clock::time_point now,
105 double left_encoder, double right_encoder,
106 double gyro_rate,
107 double /*longitudinal_accelerometer*/) override {
108 ekf_.UpdateEncodersAndGyro(left_encoder, right_encoder, gyro_rate, U, now);
109 }
110
James Kuszmaul074429e2019-03-23 16:01:49 -0700111 void ResetPosition(::aos::monotonic_clock::time_point t, double x, double y,
112 double theta) override {
James Kuszmaulfedc4612019-03-10 11:24:51 -0700113 const double left_encoder = ekf_.X_hat(StateIdx::kLeftEncoder);
114 const double right_encoder = ekf_.X_hat(StateIdx::kRightEncoder);
James Kuszmaul074429e2019-03-23 16:01:49 -0700115 ekf_.ResetInitialState(t, (Ekf::State() << x, y, theta, left_encoder, 0,
116 right_encoder, 0, 0, 0, 0).finished(),
117 ekf_.P());
James Kuszmaulef428a02019-03-02 22:19:41 -0800118 };
119
James Kuszmaul3431d622019-02-17 17:07:44 -0800120 double x() const override { return ekf_.X_hat(StateIdx::kX); }
121 double y() const override { return ekf_.X_hat(StateIdx::kY); }
122 double theta() const override { return ekf_.X_hat(StateIdx::kTheta); }
James Kuszmaul074429e2019-03-23 16:01:49 -0700123 double left_encoder() const override {
124 return ekf_.X_hat(StateIdx::kLeftEncoder);
125 }
126 double right_encoder() const override {
127 return ekf_.X_hat(StateIdx::kRightEncoder);
128 }
James Kuszmaul3431d622019-02-17 17:07:44 -0800129 double left_velocity() const override {
130 return ekf_.X_hat(StateIdx::kLeftVelocity);
131 }
132 double right_velocity() const override {
133 return ekf_.X_hat(StateIdx::kRightVelocity);
134 }
James Kuszmaul074429e2019-03-23 16:01:49 -0700135 double left_voltage_error() const override {
136 return ekf_.X_hat(StateIdx::kLeftVoltageError);
137 }
138 double right_voltage_error() const override {
139 return ekf_.X_hat(StateIdx::kRightVoltageError);
140 }
James Kuszmaul3431d622019-02-17 17:07:44 -0800141
James Kuszmaul5bc6fc92019-03-01 21:50:06 -0800142 TrivialTargetSelector *target_selector() override {
143 return &target_selector_;
144 }
145
James Kuszmaul3431d622019-02-17 17:07:44 -0800146 private:
147 Ekf ekf_;
James Kuszmaul5bc6fc92019-03-01 21:50:06 -0800148 TrivialTargetSelector target_selector_;
James Kuszmaul3431d622019-02-17 17:07:44 -0800149};
150
151} // namespace drivetrain
152} // namespace control_loops
153} // namespace frc971
154
155#endif // FRC971_CONTROL_LOOPS_DRIVETRAIN_FIELD_ESTIMATOR_H_