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:

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)));
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().

227    m_poseEstimator.update(
228        m_gyro.getRotation2d(), m_leftEncoder.getDistance(), m_rightEncoder.getDistance());
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().

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();
 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.