Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/main/java/frc/robot/Robot.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.pathplanner.lib.config.ModuleConfig;
import com.pathplanner.lib.config.RobotConfig;
import edu.wpi.first.math.geometry.*;
import edu.wpi.first.math.kinematics.ChassisSpeeds;
import edu.wpi.first.math.interpolation.Interpolator;
import edu.wpi.first.math.interpolation.TimeInterpolatableBuffer;
import edu.wpi.first.math.system.plant.DCMotor;
Expand Down Expand Up @@ -363,9 +364,13 @@ public void periodic() {
limelightRight.getIndependentRobotPose().ifPresent(poseEstimator::updateVision);
limelightLeft.getIndependentRobotPose().ifPresent(poseEstimator::updateVision);

poseEstimator.updateLastEstimatedPose();
poseEstimator.log();

ChassisSpeeds currentEstimatedVelocity = poseEstimator.getFieldRelativeEstimatedVelocity(swerve.getFieldRelativeVelocity());

ShootingCalculations
.updateShootingParams(poseEstimator.getEstimatedPose(), swerve.getFieldRelativeVelocity(), swerve.getIMUAngularVelocityRPS()[2]);
.updateShootingParams(poseEstimator.getEstimatedPose(), currentEstimatedVelocity, swerve.getIMUAngularVelocityRPS()[2]);

Logger.recordOutput("lastBallThrownTimestamp", lastBallThrownTimestamp.get());
Logger.recordOutput(
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/frc/robot/poseestimator/IPoseEstimator.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package frc.robot.poseestimator;

import edu.wpi.first.math.geometry.Pose2d;
import edu.wpi.first.math.kinematics.ChassisSpeeds;

import java.util.Optional;

Expand All @@ -17,4 +18,10 @@ public interface IPoseEstimator extends IVisionEstimator, IOdometryEstimator {

void log();

ChassisSpeeds getLastEstimatedVelocity();

void updateLastEstimatedPose();

ChassisSpeeds getFieldRelativeEstimatedVelocity(ChassisSpeeds swerveVelocity);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import edu.wpi.first.math.geometry.Pose2d;
import edu.wpi.first.math.geometry.Rotation2d;
import edu.wpi.first.math.kinematics.ChassisSpeeds;
import frc.utils.math.StandardDeviations2D;


Expand Down Expand Up @@ -35,4 +36,10 @@ public class WPILibPoseEstimatorConstants {

public static double IMU_XY_ACCELERATION_G_BUFFER_SIZE_SECONDS = 2;

/**
* Tolerance for detecting swerve wheel slip and smoothing noise. 0.5 m/s matches the skid tolerance threshold. If the difference between raw
* swerve velocity and estimated velocity exceeds this, the wheels are slipping.
*/
public static final ChassisSpeeds ESTIMATED_VELOCITY_TOLERANCE = new ChassisSpeeds(0.5, 0.5, Math.toRadians(15.0));

}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add logs

Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@
import edu.wpi.first.math.geometry.Pose2d;
import edu.wpi.first.math.geometry.Twist2d;
import edu.wpi.first.math.interpolation.TimeInterpolatableBuffer;
import edu.wpi.first.math.kinematics.SwerveDriveKinematics;
import edu.wpi.first.math.kinematics.SwerveModulePosition;
import edu.wpi.first.math.kinematics.Odometry;
import edu.wpi.first.math.kinematics.SwerveModuleState;
import edu.wpi.first.math.kinematics.*;
Comment thread
DanielShapir marked this conversation as resolved.
import edu.wpi.first.math.numbers.N1;
import edu.wpi.first.math.numbers.N3;
import frc.robot.vision.RobotPoseObservation;
import frc.robot.poseestimator.IPoseEstimator;
import frc.robot.poseestimator.OdometryData;
import frc.utils.TimedValue;
import frc.utils.buffers.RingBuffer.RingBuffer;
import frc.utils.math.StatisticsMath;
import frc.utils.math.ToleranceMath;
import frc.utils.pose.PoseUtil;
import frc.utils.time.TimeUtil;
import org.littletonrobotics.junction.Logger;

import java.util.Optional;
Expand All @@ -33,7 +33,9 @@ public class WPILibPoseEstimatorWrapper implements IPoseEstimator {
private final RingBuffer<Rotation2d> poseToIMUYawDifferenceBuffer;
private final TimeInterpolatableBuffer<Rotation2d> imuYawBuffer;
private final TimeInterpolatableBuffer<Translation2d> imuXYAccelerationGBuffer;
private RobotPoseObservation lastVisionObservation;
private final TimedValue<Pose2d> lastEstimatedPose;
private final TimedValue<ChassisSpeeds> lastEstimatedVelocity;
private RobotPoseObservation lastVisionObservation;
private OdometryData lastOdometryData;
private boolean isIMUOffsetCalibrated;

Expand Down Expand Up @@ -72,9 +74,10 @@ public WPILibPoseEstimatorWrapper(
this.imuYawBuffer = TimeInterpolatableBuffer.createBuffer(WPILibPoseEstimatorConstants.IMU_YAW_BUFFER_SIZE_SECONDS);
this.imuXYAccelerationGBuffer = TimeInterpolatableBuffer
.createBuffer(WPILibPoseEstimatorConstants.IMU_XY_ACCELERATION_G_BUFFER_SIZE_SECONDS);
this.lastEstimatedPose = new TimedValue<>(new Pose2d(), initialTimestampSeconds);
this.lastEstimatedVelocity = new TimedValue<>(new ChassisSpeeds(), initialTimestampSeconds);
}

Comment thread
DanielShapir marked this conversation as resolved.

@Override
public Pose2d getEstimatedPose() {
return poseEstimator.getEstimatedPosition();
Expand Down Expand Up @@ -131,6 +134,38 @@ public void updateVision(RobotPoseObservation... visionRobotPoseObservations) {
}
}

@Override
public void updateLastEstimatedPose() {
double timestamp = TimeUtil.getCurrentTimeSeconds();
double deltaTime = timestamp - lastEstimatedVelocity.getTimestamp();
if (deltaTime > 0) {
Pose2d currentPose = getEstimatedPose();
ChassisSpeeds rawVelocity = new ChassisSpeeds(
(currentPose.getX() - lastEstimatedPose.getValue().getX()) / deltaTime,
(currentPose.getY() - lastEstimatedPose.getValue().getY()) / deltaTime,
(currentPose.getRotation().getRadians() - lastEstimatedPose.getValue().getRotation().getRadians()) / deltaTime
);

if (ToleranceMath.isNear(new ChassisSpeeds(), rawVelocity, WPILibPoseEstimatorConstants.ESTIMATED_VELOCITY_TOLERANCE)) {
lastEstimatedVelocity.setValue(new ChassisSpeeds());
Comment on lines +149 to +150

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0.5 m/s is a very high deadband for this

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but its the deadband for skid detection
isnt the code supposed to engage only when swerve is problematic ?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You do want to have an accurate velocity either way. You have the check of wether to use it in another function

} else if (
ToleranceMath.isNear(lastEstimatedVelocity.getValue(), rawVelocity, WPILibPoseEstimatorConstants.ESTIMATED_VELOCITY_TOLERANCE)
) {
lastEstimatedVelocity.setValue(
new ChassisSpeeds(
(rawVelocity.vxMetersPerSecond + lastEstimatedVelocity.getValue().vxMetersPerSecond) / 2.0,
(rawVelocity.vyMetersPerSecond + lastEstimatedVelocity.getValue().vyMetersPerSecond) / 2.0,
(rawVelocity.omegaRadiansPerSecond + lastEstimatedVelocity.getValue().omegaRadiansPerSecond) / 2.0
)
);
}
Comment on lines +151 to +161

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why avarege the velocities if they're close?

// If neither condition is met, it is a massive vision spike. We do NOT update the value, preserving the safe velocity.
lastEstimatedVelocity.setTimestamp(timestamp);
Comment on lines +162 to +163

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you're filtering spikes you should do it by acceleration and not by velocity

}
lastEstimatedPose.setTimestamp(timestamp);
lastEstimatedPose.setValue(getEstimatedPose());
}

@Override
public void resetPose(OdometryData odometryData, Pose2d poseMeters) {
Logger.recordOutput(logPath + "/lastPoseResetTo", poseMeters);
Expand Down Expand Up @@ -226,6 +261,10 @@ private void updateVision(RobotPoseObservation visionRobotPoseObservation) {
});
}

public ChassisSpeeds getLastEstimatedVelocity() {
return lastEstimatedVelocity.getValue();
}

private void addVisionMeasurement(RobotPoseObservation visionObservation) {
poseEstimator.addVisionMeasurement(
visionObservation.robotPose(),
Expand Down Expand Up @@ -262,4 +301,16 @@ private Optional<Rotation2d> getEstimatedPoseToIMUYawDifference(Optional<Rotatio
.flatMap(estimatedPose -> gyroYaw.map(yaw -> estimatedPose.getRotation().minus(yaw)));
}

@Override
public ChassisSpeeds getFieldRelativeEstimatedVelocity(ChassisSpeeds swerveVelocity) {
if (useEstimatedVelocity(swerveVelocity, lastEstimatedVelocity.getValue())) {
return lastEstimatedVelocity.getValue();
}
return swerveVelocity;
}
Comment on lines +305 to +310

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ternary


private boolean useEstimatedVelocity(ChassisSpeeds swerveVelocity, ChassisSpeeds estimatedVelocity) {
return !ToleranceMath.isNear(swerveVelocity, estimatedVelocity, WPILibPoseEstimatorConstants.ESTIMATED_VELOCITY_TOLERANCE);
}
Comment on lines +305 to +314

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to separate to two functions


Comment thread
DanielShapir marked this conversation as resolved.
}
6 changes: 6 additions & 0 deletions src/main/java/frc/utils/math/ToleranceMath.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,10 @@ public static Rotation2d clamp(Rotation2d angle, Rotation2d minAngle, Rotation2d
return Rotation2d.fromRadians(MathUtil.clamp(angle.getRadians(), minAngle.getRadians(), maxAngle.getRadians()));
}

public static boolean isNear(ChassisSpeeds wantedSpeed, ChassisSpeeds actualSpeed, ChassisSpeeds tolerance) {
return isNear(wantedSpeed.vxMetersPerSecond, actualSpeed.vxMetersPerSecond, tolerance.vxMetersPerSecond)
&& isNear(wantedSpeed.vyMetersPerSecond, actualSpeed.vyMetersPerSecond, tolerance.vyMetersPerSecond)
&& isNear(wantedSpeed.omegaRadiansPerSecond, actualSpeed.omegaRadiansPerSecond, tolerance.omegaRadiansPerSecond);
}

}
Loading