WPILibC++ 2024.1.1-beta-4
PoseEstimator.h
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <Eigen/Core>
8#include <wpi/SymbolExports.h>
9#include <wpi/array.h>
10
11#include "frc/geometry/Pose2d.h"
17#include "units/time.h"
18#include "wpimath/MathShared.h"
19
20namespace frc {
21/**
22 * This class wraps odometry to fuse latency-compensated
23 * vision measurements with encoder measurements. Robot code should not use this
24 * directly- Instead, use the particular type for your drivetrain (e.g.,
25 * DifferentialDrivePoseEstimator). It will correct for noisy vision
26 * measurements and encoder drift. It is intended to be an easy drop-in for
27 * Odometry.
28 *
29 * Update() should be called every robot loop.
30 *
31 * AddVisionMeasurement() can be called as infrequently as you want; if you
32 * never call it, then this class will behave like regular encoder odometry.
33 */
34template <typename WheelSpeeds, WheelPositions WheelPositions>
36 public:
37 /**
38 * Constructs a PoseEstimator.
39 *
40 * @param kinematics A correctly-configured kinematics object for your
41 * drivetrain.
42 * @param odometry A correctly-configured odometry object for your drivetrain.
43 * @param stateStdDevs Standard deviations of the pose estimate (x position in
44 * meters, y position in meters, and heading in radians). Increase these
45 * numbers to trust your state estimate less.
46 * @param visionMeasurementStdDevs Standard deviations of the vision pose
47 * measurement (x position in meters, y position in meters, and heading in
48 * radians). Increase these numbers to trust the vision pose measurement
49 * less.
50 */
53 const wpi::array<double, 3>& stateStdDevs,
54 const wpi::array<double, 3>& visionMeasurementStdDevs);
55
56 /**
57 * Sets the pose estimator's trust in vision measurements. This might be used
58 * to change trust in vision measurements after the autonomous period, or to
59 * change trust as distance to a vision target increases.
60 *
61 * @param visionMeasurementStdDevs Standard deviations of the vision pose
62 * measurement (x position in meters, y position in meters, and heading in
63 * radians). Increase these numbers to trust the vision pose measurement
64 * less.
65 */
66 void SetVisionMeasurementStdDevs(
67 const wpi::array<double, 3>& visionMeasurementStdDevs);
68
69 /**
70 * Resets the robot's position on the field.
71 *
72 * The gyroscope angle does not need to be reset in the user's robot code.
73 * The library automatically takes care of offsetting the gyro angle.
74 *
75 * @param gyroAngle The current gyro angle.
76 * @param wheelPositions The distances traveled by the encoders.
77 * @param pose The estimated pose of the robot on the field.
78 */
79 void ResetPosition(const Rotation2d& gyroAngle,
80 const WheelPositions& wheelPositions, const Pose2d& pose);
81
82 /**
83 * Gets the estimated robot pose.
84 *
85 * @return The estimated robot pose in meters.
86 */
87 Pose2d GetEstimatedPosition() const;
88
89 /**
90 * Adds a vision measurement to the Kalman Filter. This will correct
91 * the odometry pose estimate while still accounting for measurement noise.
92 *
93 * This method can be called as infrequently as you want, as long as you are
94 * calling Update() every loop.
95 *
96 * To promote stability of the pose estimate and make it robust to bad vision
97 * data, we recommend only adding vision measurements that are already within
98 * one meter or so of the current pose estimate.
99 *
100 * @param visionRobotPose The pose of the robot as measured by the vision
101 * camera.
102 * @param timestamp The timestamp of the vision measurement in seconds. Note
103 * that if you don't use your own time source by calling UpdateWithTime(),
104 * then you must use a timestamp with an epoch since FPGA startup (i.e.,
105 * the epoch of this timestamp is the same epoch as
106 * frc::Timer::GetFPGATimestamp(). This means that you should use
107 * frc::Timer::GetFPGATimestamp() as your time source in this case.
108 */
109 void AddVisionMeasurement(const Pose2d& visionRobotPose,
110 units::second_t timestamp);
111
112 /**
113 * Adds a vision measurement to the Kalman Filter. This will correct
114 * the odometry pose estimate while still accounting for measurement noise.
115 *
116 * This method can be called as infrequently as you want, as long as you are
117 * calling Update() every loop.
118 *
119 * To promote stability of the pose estimate and make it robust to bad vision
120 * data, we recommend only adding vision measurements that are already within
121 * one meter or so of the current pose estimate.
122 *
123 * Note that the vision measurement standard deviations passed into this
124 * method will continue to apply to future measurements until a subsequent
125 * call to SetVisionMeasurementStdDevs() or this method.
126 *
127 * @param visionRobotPose The pose of the robot as measured by the vision
128 * camera.
129 * @param timestamp The timestamp of the vision measurement in seconds. Note
130 * that if you don't use your own time source by calling UpdateWithTime(),
131 * then you must use a timestamp with an epoch since FPGA startup (i.e.,
132 * the epoch of this timestamp is the same epoch as
133 * frc::Timer::GetFPGATimestamp(). This means that you should use
134 * frc::Timer::GetFPGATimestamp() as your time source in this case.
135 * @param visionMeasurementStdDevs Standard deviations of the vision pose
136 * measurement (x position in meters, y position in meters, and heading in
137 * radians). Increase these numbers to trust the vision pose measurement
138 * less.
139 */
141 const Pose2d& visionRobotPose, units::second_t timestamp,
142 const wpi::array<double, 3>& visionMeasurementStdDevs) {
143 SetVisionMeasurementStdDevs(visionMeasurementStdDevs);
144 AddVisionMeasurement(visionRobotPose, timestamp);
145 }
146
147 /**
148 * Updates the pose estimator with wheel encoder and gyro information. This
149 * should be called every loop.
150 *
151 * @param gyroAngle The current gyro angle.
152 * @param wheelPositions The distances traveled by the encoders.
153 *
154 * @return The estimated pose of the robot in meters.
155 */
156 Pose2d Update(const Rotation2d& gyroAngle,
157 const WheelPositions& wheelPositions);
158
159 /**
160 * Updates the pose estimator with wheel encoder and gyro information. This
161 * should be called every loop.
162 *
163 * @param currentTime The time at which this method was called.
164 * @param gyroAngle The current gyro angle.
165 * @param wheelPositions The distances traveled by the encoders.
166 *
167 * @return The estimated pose of the robot in meters.
168 */
169 Pose2d UpdateWithTime(units::second_t currentTime,
170 const Rotation2d& gyroAngle,
171 const WheelPositions& wheelPositions);
172
173 private:
174 struct InterpolationRecord {
175 // The pose observed given the current sensor inputs and the previous pose.
176 Pose2d pose;
177
178 // The current gyroscope angle.
179 Rotation2d gyroAngle;
180
181 // The distances traveled by the wheels.
182 WheelPositions wheelPositions;
183
184 /**
185 * Checks equality between this InterpolationRecord and another object.
186 *
187 * @param other The other object.
188 * @return Whether the two objects are equal.
189 */
190 bool operator==(const InterpolationRecord& other) const = default;
191
192 /**
193 * Checks inequality between this InterpolationRecord and another object.
194 *
195 * @param other The other object.
196 * @return Whether the two objects are not equal.
197 */
198 bool operator!=(const InterpolationRecord& other) const = default;
199
200 /**
201 * Interpolates between two InterpolationRecords.
202 *
203 * @param endValue The end value for the interpolation.
204 * @param i The interpolant (fraction).
205 *
206 * @return The interpolated state.
207 */
208 InterpolationRecord Interpolate(
210 InterpolationRecord endValue, double i) const;
211 };
212
213 static constexpr units::second_t kBufferDuration = 1.5_s;
214
215 Kinematics<WheelSpeeds, WheelPositions>& m_kinematics;
216 Odometry<WheelSpeeds, WheelPositions>& m_odometry;
218 Eigen::Matrix3d m_visionK = Eigen::Matrix3d::Zero();
219
220 TimeInterpolatableBuffer<InterpolationRecord> m_poseBuffer{
221 kBufferDuration, [this](const InterpolationRecord& start,
222 const InterpolationRecord& end, double t) {
223 return start.Interpolate(this->m_kinematics, end, t);
224 }};
225};
226} // namespace frc
227
#define WPILIB_DLLEXPORT
Definition: SymbolExports.h:36
Helper class that converts a chassis velocity (dx, dy, and dtheta components) into individual wheel s...
Definition: Kinematics.h:23
Class for odometry.
Definition: Odometry.h:25
Represents a 2D pose containing translational and rotational elements.
Definition: Pose2d.h:23
This class wraps odometry to fuse latency-compensated vision measurements with encoder measurements.
Definition: PoseEstimator.h:35
void AddVisionMeasurement(const Pose2d &visionRobotPose, units::second_t timestamp, const wpi::array< double, 3 > &visionMeasurementStdDevs)
Adds a vision measurement to the Kalman Filter.
Definition: PoseEstimator.h:140
A rotation in a 2D coordinate frame represented by a point on the unit circle (cosine and sine).
Definition: Rotation2d.h:23
Definition: WheelPositions.h:11
Definition: AprilTagPoseEstimator.h:15
bool operator==(const Value &lhs, const Value &rhs)
constexpr bool operator!=(const UNIT_LIB_DEFAULT_TYPE lhs, const Units &rhs) noexcept
Definition: base.h:2728
constexpr empty_array_t empty_array
Definition: array.h:16