001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.math.estimator;
006
007import edu.wpi.first.math.Matrix;
008import edu.wpi.first.math.VecBuilder;
009import edu.wpi.first.math.geometry.Pose2d;
010import edu.wpi.first.math.geometry.Pose3d;
011import edu.wpi.first.math.geometry.Rotation2d;
012import edu.wpi.first.math.geometry.Rotation3d;
013import edu.wpi.first.math.geometry.Translation2d;
014import edu.wpi.first.math.geometry.Translation3d;
015import edu.wpi.first.math.kinematics.DifferentialDriveKinematics;
016import edu.wpi.first.math.kinematics.DifferentialDriveOdometry3d;
017import edu.wpi.first.math.kinematics.DifferentialDriveWheelPositions;
018import edu.wpi.first.math.numbers.N1;
019import edu.wpi.first.math.numbers.N4;
020
021/**
022 * This class wraps {@link DifferentialDriveOdometry3d Differential Drive Odometry} to fuse
023 * latency-compensated vision measurements with differential drive encoder measurements. It is
024 * intended to be a drop-in replacement for {@link DifferentialDriveOdometry3d}; in fact, if you
025 * never call {@link DifferentialDrivePoseEstimator3d#addVisionMeasurement} and only call {@link
026 * DifferentialDrivePoseEstimator3d#update} then this will behave exactly the same as
027 * DifferentialDriveOdometry3d. It is also intended to be an easy replacement for {@link
028 * DifferentialDrivePoseEstimator}, only requiring the addition of a standard deviation for Z and
029 * appropriate conversions between 2D and 3D versions of geometry classes. (See {@link
030 * Pose3d#Pose3d(Pose2d)}, {@link Rotation3d#Rotation3d(Rotation2d)}, {@link
031 * Translation3d#Translation3d(Translation2d)}, and {@link Pose3d#toPose2d()}.)
032 *
033 * <p>{@link DifferentialDrivePoseEstimator3d#update} should be called every robot loop.
034 *
035 * <p>{@link DifferentialDrivePoseEstimator3d#addVisionMeasurement} can be called as infrequently as
036 * you want; if you never call it then this class will behave exactly like regular encoder odometry.
037 */
038public class DifferentialDrivePoseEstimator3d
039    extends PoseEstimator3d<DifferentialDriveWheelPositions> {
040  /**
041   * Constructs a DifferentialDrivePoseEstimator3d with default standard deviations for the model
042   * and vision measurements.
043   *
044   * <p>The default standard deviations of the model states are 0.02 meters for x, 0.02 meters for
045   * y, 0.02 meters for z, and 0.01 radians for angle. The default standard deviations of the vision
046   * measurements are 0.1 meters for x, 0.1 meters for y, 0.1 meters for z, and 0.1 radians for
047   * angle.
048   *
049   * @param kinematics A correctly-configured kinematics object for your drivetrain.
050   * @param gyroAngle The current gyro angle.
051   * @param leftDistanceMeters The distance traveled by the left encoder.
052   * @param rightDistanceMeters The distance traveled by the right encoder.
053   * @param initialPoseMeters The starting pose estimate.
054   */
055  public DifferentialDrivePoseEstimator3d(
056      DifferentialDriveKinematics kinematics,
057      Rotation3d gyroAngle,
058      double leftDistanceMeters,
059      double rightDistanceMeters,
060      Pose3d initialPoseMeters) {
061    this(
062        kinematics,
063        gyroAngle,
064        leftDistanceMeters,
065        rightDistanceMeters,
066        initialPoseMeters,
067        VecBuilder.fill(0.02, 0.02, 0.02, 0.01),
068        VecBuilder.fill(0.1, 0.1, 0.1, 0.1));
069  }
070
071  /**
072   * Constructs a DifferentialDrivePoseEstimator3d.
073   *
074   * @param kinematics A correctly-configured kinematics object for your drivetrain.
075   * @param gyroAngle The gyro angle of the robot.
076   * @param leftDistanceMeters The distance traveled by the left encoder.
077   * @param rightDistanceMeters The distance traveled by the right encoder.
078   * @param initialPoseMeters The estimated initial pose.
079   * @param stateStdDevs Standard deviations of the pose estimate (x position in meters, y position
080   *     in meters, and heading in radians). Increase these numbers to trust your state estimate
081   *     less.
082   * @param visionMeasurementStdDevs Standard deviations of the vision pose measurement (x position
083   *     in meters, y position in meters, and heading in radians). Increase these numbers to trust
084   *     the vision pose measurement less.
085   */
086  public DifferentialDrivePoseEstimator3d(
087      DifferentialDriveKinematics kinematics,
088      Rotation3d gyroAngle,
089      double leftDistanceMeters,
090      double rightDistanceMeters,
091      Pose3d initialPoseMeters,
092      Matrix<N4, N1> stateStdDevs,
093      Matrix<N4, N1> visionMeasurementStdDevs) {
094    super(
095        kinematics,
096        new DifferentialDriveOdometry3d(
097            gyroAngle, leftDistanceMeters, rightDistanceMeters, initialPoseMeters),
098        stateStdDevs,
099        visionMeasurementStdDevs);
100  }
101
102  /**
103   * Resets the robot's position on the field.
104   *
105   * <p>The gyroscope angle does not need to be reset here on the user's robot code. The library
106   * automatically takes care of offsetting the gyro angle.
107   *
108   * @param gyroAngle The angle reported by the gyroscope.
109   * @param leftPositionMeters The distance traveled by the left encoder.
110   * @param rightPositionMeters The distance traveled by the right encoder.
111   * @param poseMeters The position on the field that your robot is at.
112   */
113  public void resetPosition(
114      Rotation3d gyroAngle,
115      double leftPositionMeters,
116      double rightPositionMeters,
117      Pose3d poseMeters) {
118    resetPosition(
119        gyroAngle,
120        new DifferentialDriveWheelPositions(leftPositionMeters, rightPositionMeters),
121        poseMeters);
122  }
123
124  /**
125   * Updates the pose estimator with wheel encoder and gyro information. This should be called every
126   * loop.
127   *
128   * @param gyroAngle The current gyro angle.
129   * @param distanceLeftMeters The total distance travelled by the left wheel in meters.
130   * @param distanceRightMeters The total distance travelled by the right wheel in meters.
131   * @return The estimated pose of the robot in meters.
132   */
133  public Pose3d update(
134      Rotation3d gyroAngle, double distanceLeftMeters, double distanceRightMeters) {
135    return update(
136        gyroAngle, new DifferentialDriveWheelPositions(distanceLeftMeters, distanceRightMeters));
137  }
138
139  /**
140   * Updates the pose estimator with wheel encoder and gyro information. This should be called every
141   * loop.
142   *
143   * @param currentTimeSeconds Time at which this method was called, in seconds.
144   * @param gyroAngle The current gyro angle.
145   * @param distanceLeftMeters The total distance travelled by the left wheel in meters.
146   * @param distanceRightMeters The total distance travelled by the right wheel in meters.
147   * @return The estimated pose of the robot in meters.
148   */
149  public Pose3d updateWithTime(
150      double currentTimeSeconds,
151      Rotation3d gyroAngle,
152      double distanceLeftMeters,
153      double distanceRightMeters) {
154    return updateWithTime(
155        currentTimeSeconds,
156        gyroAngle,
157        new DifferentialDriveWheelPositions(distanceLeftMeters, distanceRightMeters));
158  }
159}