36template <
size_t NumModules>
61 modulePositions, initialPose,
62 {0.1, 0.1, 0.1}, {0.9, 0.9, 0.9}} {}
87 : m_kinematics{kinematics},
88 m_odometry{kinematics, gyroAngle, modulePositions, initialPose} {
89 for (
size_t i = 0; i < 3; ++i) {
90 m_q[i] = stateStdDevs[i] * stateStdDevs[i];
93 SetVisionMeasurementStdDevs(visionMeasurementStdDevs);
112 m_odometry.ResetPosition(gyroAngle, modulePositions, pose);
113 m_poseBuffer.Clear();
136 for (
size_t i = 0; i < 3; ++i) {
137 r[i] = visionMeasurementStdDevs[i] * visionMeasurementStdDevs[i];
143 if (m_q[
row] == 0.0) {
144 m_visionK(
row,
row) = 0.0;
173 units::second_t timestamp) {
176 if (!m_poseBuffer.GetInternalBuffer().empty() &&
177 m_poseBuffer.GetInternalBuffer().front().first - kBufferDuration >
183 auto sample = m_poseBuffer.Sample(timestamp);
185 if (!sample.has_value()) {
190 auto twist = sample.value().pose.Log(visionRobotPose);
197 twist.dtheta.value()};
200 Twist2d scaledTwist{units::meter_t{k_times_twist(0)},
201 units::meter_t{k_times_twist(1)},
202 units::radian_t{k_times_twist(2)}};
205 m_odometry.ResetPosition(sample.value().gyroAngle,
206 sample.value().modulePositions,
207 sample.value().pose.Exp(scaledTwist));
211 m_poseBuffer.AddSample(timestamp,
212 {GetEstimatedPosition(), sample.value().gyroAngle,
213 sample.value().modulePositions});
217 auto internal_buf = m_poseBuffer.GetInternalBuffer();
219 auto upper_bound = std::lower_bound(
220 internal_buf.begin(), internal_buf.end(), timestamp,
221 [](
const auto& pair,
auto t) { return t > pair.first; });
223 for (
auto entry = upper_bound; entry != internal_buf.end(); entry++) {
224 UpdateWithTime(entry->first, entry->second.gyroAngle,
225 entry->second.modulePositions);
258 const Pose2d& visionRobotPose, units::second_t timestamp,
260 SetVisionMeasurementStdDevs(visionMeasurementStdDevs);
261 AddVisionMeasurement(visionRobotPose, timestamp);
291 units::second_t currentTime,
const Rotation2d& gyroAngle,
293 m_odometry.Update(gyroAngle, modulePositions);
298 for (
size_t i = 0; i < NumModules; i++) {
299 internalModulePositions[i].distance = modulePositions[i].distance;
300 internalModulePositions[i].angle = modulePositions[i].angle;
303 m_poseBuffer.AddSample(currentTime, {GetEstimatedPosition(), gyroAngle,
304 internalModulePositions});
306 return GetEstimatedPosition();
310 struct InterpolationRecord {
326 bool operator==(
const InterpolationRecord& other)
const =
default;
334 bool operator!=(
const InterpolationRecord& other)
const =
default;
344 InterpolationRecord Interpolate(
346 InterpolationRecord endValue,
double i)
const {
360 for (
size_t i = 0; i < NumModules; i++) {
361 modulePositions[i].distance =
362 wpi::Lerp(this->modulePositions[i].distance,
363 endValue.modulePositions[i].distance, i);
364 modulePositions[i].angle =
365 wpi::Lerp(this->modulePositions[i].angle,
366 endValue.modulePositions[i].angle, i);
368 modulesDelta[i].distance =
369 modulePositions[i].distance - this->modulePositions[i].distance;
370 modulesDelta[i].angle = modulePositions[i].angle;
374 auto gyro =
wpi::Lerp(this->gyroAngle, endValue.gyroAngle, i);
378 auto twist = kinematics.
ToTwist2d(modulesDelta);
379 twist.
dtheta = (gyro - gyroAngle).Radians();
381 return {pose.
Exp(twist), gyro, modulePositions};
386 static constexpr units::second_t kBufferDuration = 1.5_s;
388 SwerveDriveKinematics<NumModules>& m_kinematics;
389 SwerveDriveOdometry<NumModules> m_odometry;
391 Eigen::Matrix3d m_visionK = Eigen::Matrix3d::Zero();
393 TimeInterpolatableBuffer<InterpolationRecord> m_poseBuffer{
394 kBufferDuration, [
this](
const InterpolationRecord& start,
395 const InterpolationRecord&
end,
double t) {
396 return start.Interpolate(this->m_kinematics,
end, t);
401 SwerveDrivePoseEstimator<4>;
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE RowXpr row(Index i)
This is the const version of row(). */.
Definition: BlockMethods.h:1118
#define EXPORT_TEMPLATE_DECLARE(export)
Definition: SymbolExports.h:94
#define WPILIB_DLLEXPORT
Definition: SymbolExports.h:36
Represents a 2D pose containing translational and rotational elements.
Definition: Pose2d.h:25
Pose2d Exp(const Twist2d &twist) const
Obtain a new Pose2d from a (constant curvature) velocity.
A rotation in a 2D coordinate frame represented by a point on the unit circle (cosine and sine).
Definition: Rotation2d.h:26
Helper class that converts a chassis velocity (dx, dy, and dtheta components) into individual module ...
Definition: SwerveDriveKinematics.h:47
Twist2d ToTwist2d(ModuleDeltas &&... wheelDeltas) const
Performs forward kinematics to return the resulting Twist2d from the given module position deltas.
Definition: SwerveDriveKinematics.inc:101
This class wraps Swerve Drive Odometry to fuse latency-compensated vision measurements with swerve dr...
Definition: SwerveDrivePoseEstimator.h:37
void AddVisionMeasurement(const Pose2d &visionRobotPose, units::second_t timestamp, const wpi::array< double, 3 > &visionMeasurementStdDevs)
Adds a vision measurement to the Kalman Filter.
Definition: SwerveDrivePoseEstimator.h:257
Pose2d Update(const Rotation2d &gyroAngle, const wpi::array< SwerveModulePosition, NumModules > &modulePositions)
Updates the pose estimator with wheel encoder and gyro information.
Definition: SwerveDrivePoseEstimator.h:273
void ResetPosition(const Rotation2d &gyroAngle, const wpi::array< SwerveModulePosition, NumModules > &modulePositions, const Pose2d &pose)
Resets the robot's position on the field.
Definition: SwerveDrivePoseEstimator.h:107
SwerveDrivePoseEstimator(SwerveDriveKinematics< NumModules > &kinematics, const Rotation2d &gyroAngle, const wpi::array< SwerveModulePosition, NumModules > &modulePositions, const Pose2d &initialPose, const wpi::array< double, 3 > &stateStdDevs, const wpi::array< double, 3 > &visionMeasurementStdDevs)
Constructs a SwerveDrivePoseEstimator.
Definition: SwerveDrivePoseEstimator.h:81
void SetVisionMeasurementStdDevs(const wpi::array< double, 3 > &visionMeasurementStdDevs)
Sets the pose estimator's trust in vision measurements.
Definition: SwerveDrivePoseEstimator.h:133
Pose2d UpdateWithTime(units::second_t currentTime, const Rotation2d &gyroAngle, const wpi::array< SwerveModulePosition, NumModules > &modulePositions)
Updates the pose estimator with wheel encoder and gyro information.
Definition: SwerveDrivePoseEstimator.h:290
SwerveDrivePoseEstimator(SwerveDriveKinematics< NumModules > &kinematics, const Rotation2d &gyroAngle, const wpi::array< SwerveModulePosition, NumModules > &modulePositions, const Pose2d &initialPose)
Constructs a SwerveDrivePoseEstimator with default standard deviations for the model and vision measu...
Definition: SwerveDrivePoseEstimator.h:55
void AddVisionMeasurement(const Pose2d &visionRobotPose, units::second_t timestamp)
Adds a vision measurement to the Kalman Filter.
Definition: SwerveDrivePoseEstimator.h:172
Pose2d GetEstimatedPosition() const
Gets the estimated robot pose.
Definition: SwerveDrivePoseEstimator.h:121
This class is a wrapper around std::array that does compile time size checking.
Definition: array.h:25
static units::second_t GetTimestamp()
Definition: MathShared.h:77
auto sqrt(const UnitType &value) noexcept -> unit_t< square_root< typename units::traits::unit_t_traits< UnitType >::unit_type >, typename units::traits::unit_t_traits< UnitType >::underlying_type, linear_scale >
computes the square root of value
Definition: math.h:483
static EIGEN_DEPRECATED const end_t end
Definition: IndexedViewHelper.h:181
Definition: AprilTagFieldLayout.h:22
Eigen::Vector< double, Size > Vectord
Definition: EigenCore.h:12
bool operator==(const Value &lhs, const Value &rhs)
constexpr bool operator!=(const UNIT_LIB_DEFAULT_TYPE lhs, const Units &rhs) noexcept
Definition: base.h:2716
constexpr T Lerp(const T &startValue, const T &endValue, double t)
Linearly interpolates between two values.
Definition: MathExtras.h:950
constexpr empty_array_t empty_array
Definition: array.h:15
A change in distance along a 2D arc since the last pose update.
Definition: Twist2d.h:21
units::radian_t dtheta
Angular "dtheta" component (radians)
Definition: Twist2d.h:35