- FRC Game Manual
- FRC Game Q&A

# Pose Estimators

WPILib includes pose estimators for differential, swerve, and mecanum drivetrains. These estimators are designed to be drop-in replacements for the existing odometry classes that also support fusing latency-compensated robot pose estimates with encoder and gyro measurements. These estimators can account for encoder drift and noisy vision data. These estimators can behave identically to their corresponding odometry classes if only `update` is called on these estimators.

Pose estimators estimate robot position using a state-space system with the states \(\begin{bmatrix}x & y & \theta \end{bmatrix}^T\), which can represent robot position as a `Pose2d`. WPILib includes `DifferentialDrivePoseEstimator`, `SwerveDrivePoseEstimator` and `MecanumDrivePoseEstimator` to estimate robot position. In these, users call `update` periodically with encoder and gyro measurements (same as the odometry classes) to update the robot’s estimated position. When the robot receives measurements of its field-relative position (encoded as a `Pose2d`) from sensors such as computer vision or V-SLAM, the pose estimator latency-compensates the measurement to accurately estimate robot position.

Here’s how to initialize a `DifferentialDrivePoseEstimator`:

JAVA

    86  private final DifferentialDrivePoseEstimator m_poseEstimator =
    87      new DifferentialDrivePoseEstimator(
    88          m_kinematics,
    89          m_gyro.getRotation2d(),
    90          m_leftEncoder.getDistance(),
    91          m_rightEncoder.getDistance(),
    92          new Pose2d(),
    93          VecBuilder.fill(0.05, 0.05, Units.degreesToRadians(5)),
    94          VecBuilder.fill(0.5, 0.5, Units.degreesToRadians(30)));

C++

    158  frc::DifferentialDrivePoseEstimator m_poseEstimator{
    159      m_kinematics,
    160      m_gyro.GetRotation2d(),
    161      units::meter_t{m_leftEncoder.GetDistance()},
    162      units::meter_t{m_rightEncoder.GetDistance()},
    163      frc::Pose2d{},
    164      {0.01, 0.01, 0.01},
    165      {0.1, 0.1, 0.1}};

Add odometry measurements every loop by calling `Update()`.

JAVA

    227    m_poseEstimator.update(
    228        m_gyro.getRotation2d(), m_leftEncoder.getDistance(), m_rightEncoder.getDistance());

C++

    84  m_poseEstimator.Update(m_gyro.GetRotation2d(),
    85                         units::meter_t{m_leftEncoder.GetDistance()},
    86                         units::meter_t{m_rightEncoder.GetDistance()});

Add vision pose measurements occasionally by calling `AddVisionMeasurement()`.

JAVA

    236    // Compute the robot's field-relative position exclusively from vision measurements.
    237    Pose3d visionMeasurement3d =
    238        objectToRobotPose(m_objectInField, m_robotToCamera, m_cameraToObjectEntry);
    239
    240    // Convert robot pose from Pose3d to Pose2d needed to apply vision measurements.
    241    Pose2d visionMeasurement2d = visionMeasurement3d.toPose2d();
    242
    243    // Apply vision measurements. For simulation purposes only, we don't input a latency delay -- on
    244    // a real robot, this must be calculated based either on known latency or timestamps.
    245    m_poseEstimator.addVisionMeasurement(visionMeasurement2d, Timer.getFPGATimestamp());

C++

     93  // Compute the robot's field-relative position exclusively from vision
     94  // measurements.
     95  frc::Pose3d visionMeasurement3d = ObjectToRobotPose(
     96      m_objectInField, m_robotToCamera, m_cameraToObjectEntryRef);
     97
     98  // Convert robot's pose from Pose3d to Pose2d needed to apply vision
     99  // measurements.
    100  frc::Pose2d visionMeasurement2d = visionMeasurement3d.ToPose2d();
    101
    102  // Apply vision measurements. For simulation purposes only, we don't input a
    103  // latency delay -- on a real robot, this must be calculated based either on
    104  // known latency or timestamps.
    105  m_poseEstimator.AddVisionMeasurement(visionMeasurement2d,
    106                                       frc::Timer::GetFPGATimestamp());

## Tuning Pose Estimators

All pose estimators offer user-customizable standard deviations for model and measurements (defaults are used if you don’t provide them). Standard deviation is a measure of how spread out the noise is for a random signal. Giving a state a smaller standard deviation means it will be trusted more during data fusion.

For example, increasing the standard deviation for measurements (as one might do for a noisy signal) would lead to the estimator trusting its state estimate more than the incoming measurements. On the field, this might mean that the filter can reject noisy vision data well, at the cost of being slow to correct for model deviations. While these values can be estimated beforehand, they very much depend on the unique setup of each robot and global measurement method.

When incorporating AprilTag poses, make the vision heading standard deviation very large, make the gyro heading standard deviation small, and scale the vision x and y standard deviation by distance from the tag.