Skip to content

Commit

Permalink
Merge pull request #17 from acuaroo/main
Browse files Browse the repository at this point in the history
Added vision to odometry
  • Loading branch information
zaneal authored Jan 27, 2024
2 parents e8dccf9 + 6b4e7c9 commit 2088a4e
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 41 deletions.
8 changes: 4 additions & 4 deletions src/main/java/frc/robot/RobotContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,20 @@ public class RobotContainer {
public XboxController primaryController = new XboxController(0);
public XboxController secondaryController = new XboxController(1);
public SwerveSubsystem swerveSubsystem = new SwerveSubsystem();

/** The container for the robot. Contains subsystems, OI devices, and commands. */
public RobotContainer() {
// Configure the button bindings
// configureButtonBindings();
configureButtonBindings();
}

public void configureButtonBindings(){

swerveSubsystem.setDefaultCommand(new DriveCommands(
swerveSubsystem,
() -> primaryController.getLeftY() * DrivetrainConstants.drivingSpeedScalar / 1.0,
() -> primaryController.getLeftX() * DrivetrainConstants.drivingSpeedScalar / 1.0,
() -> primaryController.getRightX() * DrivetrainConstants.rotationSpeedScalar / 1.0,
() -> primaryController.getLeftY() * DrivetrainConstants.drivingSpeedScalar / 2.0,
() -> primaryController.getLeftX() * DrivetrainConstants.drivingSpeedScalar / 2.0,
() -> primaryController.getRightX() * DrivetrainConstants.rotationSpeedScalar / 2.0,
true,
true
));
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/frc/robot/constants/DrivetrainConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ public class DrivetrainConstants {
public static final double magnitudeSlewRate = 5.0; // percent/second (1 = 100%) - forward/backward/traverse
public static final double rotationalSlewRate = 12.0; // percent/second (1 = 100%) - rotation

public static final double drivingSpeedScalar = -1.0;
public static final double rotationSpeedScalar = 2.0;
public static final double drivingSpeedScalar = 1.0;
public static final double rotationSpeedScalar = -2.0;

public static final double trackWidth = Units.inchesToMeters(18);
public static final double wheelBase = Units.inchesToMeters(22.5);
Expand All @@ -27,10 +27,10 @@ public class DrivetrainConstants {
new Translation2d(-wheelBase / 2, -trackWidth / 2)
);

public static final double frontLeftChassisAngularOffset = -0.57 + Math.PI;
public static final double frontRightChassisAngularOffset = 0.874 + Math.PI;
public static final double rearLeftChassisAngularOffset = 6.098;
public static final double rearRightChassisAngularOffset = 5.52 - Math.PI/2;
public static final double frontLeftChassisAngularOffset = -0.57 ;
public static final double frontRightChassisAngularOffset = 0.874;
public static final double rearLeftChassisAngularOffset = 6.098 + Math.PI;
public static final double rearRightChassisAngularOffset = 5.52 + Math.PI/2;

public static final int frontLeftDrivingPort = 1;
public static final int rearLeftDrivingPort = 5;
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/frc/robot/constants/VisionConstants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package frc.robot.constants;

import edu.wpi.first.math.trajectory.TrapezoidProfile;

public class VisionConstants {
public static final double alignXP = 0.9;
public static final double alignXI = 0;
public static final double alignXD = 0;
public static final TrapezoidProfile.Constraints alignXConstraints = new TrapezoidProfile.Constraints(0.75, 0.5);

public static final double alignZP = 0.6;
public static final double alignZI = 0;
public static final double alignZD = 0;
public static final TrapezoidProfile.Constraints alignZConstraints = new TrapezoidProfile.Constraints(0.75, 0.5);

public static final double alignRotationP = 0.6;
public static final double alignRotationI = 0;
public static final double alignRotationD = 0;
public static final TrapezoidProfile.Constraints alignRotationConstraints = new TrapezoidProfile.Constraints(0.75, 0.5);
}
100 changes: 70 additions & 30 deletions src/main/java/frc/robot/subsystems/SwerveSubsystem.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
package frc.robot.subsystems;

import com.kauailabs.navx.frc.AHRS;
import edu.wpi.first.math.VecBuilder;
import edu.wpi.first.math.estimator.SwerveDrivePoseEstimator;
import edu.wpi.first.math.geometry.Pose2d;
import edu.wpi.first.math.filter.SlewRateLimiter;
import edu.wpi.first.math.geometry.Pose2d;
import edu.wpi.first.math.geometry.Pose3d;
import edu.wpi.first.math.geometry.Rotation2d;
import edu.wpi.first.math.geometry.Translation2d;
import edu.wpi.first.math.kinematics.*;
import edu.wpi.first.math.util.Units;
import edu.wpi.first.networktables.DoubleArrayEntry;
import edu.wpi.first.networktables.DoubleEntry;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.util.WPIUtilJNI;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj2.command.SubsystemBase;
import frc.robot.constants.DrivetrainConstants;;
import frc.robot.constants.DrivetrainConstants;
import frc.robot.controllers.SwerveModuleControlller;
import frc.robot.utils.NetworkTableUtils;
import frc.robot.utils.SwerveUtils;
import java.util.Arrays;

import frc.robot.utils.VisionUtils;

public class SwerveSubsystem extends SubsystemBase {
// Defining Motors
Expand Down Expand Up @@ -65,14 +70,13 @@ public class SwerveSubsystem extends SubsystemBase {
// Relay data to driverstation using network table
private final NetworkTableUtils limelightTable = new NetworkTableUtils("limelight");

// Convert Gyro angle to radians (-2pi to 2pi)
// Makes some robot direction math stuff easier than degrees?
// Convert Gyro angle to radians(-2pi to 2pi)
public double heading() {
return Units.degreesToRadians(-1 * (gyro.getAngle() + 180.0) % 360.0);
}

// Swerve Odometry
// Tracks changes in robot position?
/*
private final SwerveDriveOdometry odometry = new SwerveDriveOdometry(
DrivetrainConstants.driveKinematics,
Rotation2d.fromRadians(heading()),
Expand All @@ -83,6 +87,25 @@ public double heading() {
rearRight.getPosition()
}
);
*/

private double distanceToTag = 1.0;
private final SwerveDrivePoseEstimator poseEstimator = new SwerveDrivePoseEstimator(
DrivetrainConstants.driveKinematics,
gyro.getRotation2d(),
new SwerveModulePosition[] {
frontLeft.getPosition(),
frontRight.getPosition(),
rearLeft.getPosition(),
rearRight.getPosition()
},
new Pose2d(),

// How much we trust the wheel measurements
VecBuilder.fill(0.05, 0.05, Units.degreesToRadians(10)),

// How much we trust the vision measurements
VecBuilder.fill(0.05 * distanceToTag, 0.05 * distanceToTag, Units.degreesToRadians(30 * (distanceToTag / 5.0))));

// Network Tables Telemetry
private final DoubleArrayEntry setpointsTelemetry = NetworkTableInstance.getDefault()
Expand All @@ -91,9 +114,9 @@ public double heading() {
.getTable("Swerve").getDoubleArrayTopic("Actual").getEntry(new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0});

private final DoubleArrayEntry poseTelemetry = NetworkTableInstance.getDefault()
.getTable("Swerve").getDoubleArrayTopic("Pose").getEntry(new double[]{odometry.getPoseMeters().getTranslation().getX(),
odometry.getPoseMeters().getTranslation().getY(),
odometry.getPoseMeters().getRotation().getRadians()});
.getTable("Swerve").getDoubleArrayTopic("Pose").getEntry(new double[]{poseEstimator.getEstimatedPosition().getTranslation().getX(),
poseEstimator.getEstimatedPosition().getTranslation().getY(),
poseEstimator.getEstimatedPosition().getRotation().getRadians()});

private final DoubleEntry gyroHeading = NetworkTableInstance.getDefault()
.getTable("Swerve").getDoubleTopic("GyroHeading").getEntry(heading());
Expand All @@ -111,15 +134,10 @@ public double heading() {
.getTable("Swerve").getDoubleTopic("rlpos").getEntry(rearLeft.getPosition().angle.getRadians());

// Periodic

/**
* Periodically updates swerve module position.
**/

@Override
public void periodic() {
// Update odometry
odometry.update(
// Add wheel measurements to odometry
poseEstimator.update(
Rotation2d.fromRadians(heading()),
new SwerveModulePosition[]{
frontLeft.getPosition(),
Expand All @@ -129,13 +147,37 @@ public void periodic() {
}
);

// Coen's Vision Lineup Thing:
// find the botpose network table id thingy, construct a pose2d, feed it into resetodometry
// double[] botpose = limelightTable.getDoubleArray("botpose", new double[0]);
// if (!Arrays.equals(botpose, new double[0])) {
// Pose2d pose = new Pose2d(new Translation2d(botpose[0], botpose[2]), new Rotation2d(botpose[3], botpose[5]));
// resetOdometry(pose);
// }
// Add vision measurement to odometry
Pose3d visionMeasurement = VisionUtils.getBotPoseFieldSpace();

if (visionMeasurement.getY() != 0 || visionMeasurement.getX() != 0) {
distanceToTag = VisionUtils.getDistanceFromTag();

double visionTrust = 0.075 * Math.pow(distanceToTag, 2.5);
double rotationVisionTrust = Math.pow(distanceToTag, 2.5) / 5;

if (distanceToTag < 3) {
poseEstimator.setVisionMeasurementStdDevs(
VecBuilder.fill(
visionTrust,
visionTrust,
Units.degreesToRadians(20 * ((distanceToTag < 1.5) ? rotationVisionTrust : 9999))
)
);
} else {
// If we're 3 meters away, limelight is too unreliable. Don't trust it!
poseEstimator.setVisionMeasurementStdDevs(
VecBuilder.fill(9999, 9999, 9999)
);
}

poseEstimator.addVisionMeasurement(
new Pose2d(
new Translation2d(visionMeasurement.getX(), visionMeasurement.getY()),
new Rotation2d(visionMeasurement.getRotation().toRotation2d().getRadians())
),
Timer.getFPGATimestamp() - (VisionUtils.getLatencyPipeline()/1000.0) - (VisionUtils.getLatencyCapture()/1000.0));
}

frontrightpos.set(frontRight.getPosition().angle.getRadians());
frontleftpos.set(frontLeft.getPosition().angle.getRadians());
Expand All @@ -156,9 +198,9 @@ public void periodic() {
rearRight.getDesiredState().angle.getRadians(), rearRight.getDesiredState().speedMetersPerSecond});

poseTelemetry.set(new double[]{
odometry.getPoseMeters().getTranslation().getX(),
odometry.getPoseMeters().getTranslation().getY(),
odometry.getPoseMeters().getRotation().getRadians()
poseEstimator.getEstimatedPosition().getTranslation().getX(),
poseEstimator.getEstimatedPosition().getTranslation().getY(),
poseEstimator.getEstimatedPosition().getRotation().getRadians()
});

gyroHeading.set(heading());
Expand All @@ -170,19 +212,17 @@ public void periodic() {
* Get robot's pose.
*/
private Pose2d getPose() {
return odometry.getPoseMeters();
return poseEstimator.getEstimatedPosition();
}

//Useful functions for testing, calibration:

// Reset odometry function

/**
* @param pose Reset robot's position.
*/

private void resetOdometry(Pose2d pose) {
odometry.resetPosition(
poseEstimator.resetPosition(
Rotation2d.fromRadians(heading()),
new SwerveModulePosition[]{
frontLeft.getPosition(),
Expand Down
70 changes: 70 additions & 0 deletions src/main/java/frc/robot/utils/VisionUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package frc.robot.utils;

import edu.wpi.first.math.geometry.*;

import edu.wpi.first.networktables.NetworkTableInstance;

import edu.wpi.first.wpilibj.DriverStation;

public class VisionUtils {
/**
* Gets the requested entry from as well as optionally adding the alliance. Used internally
* @param pose The pose you want as defined by https://docs.limelightvision.io/docs/docs-limelight/apis/complete-networktables-api#apriltag-and-3d-data
* @param useAlliance Whether to add on the alliance
* @return The pose from the limelight
*/
private static Pose3d getPose(String pose, boolean useAlliance) {
String suffix = (useAlliance && DriverStation.getAlliance().isPresent()) ?
((DriverStation.getAlliance().get() == DriverStation.Alliance.Blue) ? "_wpiblue" : "_wpired") : "";

double[] returnedPose = NetworkTableInstance.getDefault().getTable("limelight").getEntry(pose + suffix).getDoubleArray(new double[0]);
if (returnedPose.length == 0) return new Pose3d();

return new Pose3d(
new Translation3d(returnedPose[0], returnedPose[1], returnedPose[2]),
new Rotation3d(0.0, 0.0, Math.toRadians(returnedPose[5]))
);
}

/**
* Gets the bots position relative to the field. Used by odometry
* @return The bots position
* */
public static Pose3d getBotPoseFieldSpace() {
return getPose("botpose", true);
}

/**
* Gets the bots position relative to the target. Used by AlignCommand
* @return The bots position
* */
public static Pose3d getBotPoseTargetSpace() {
return getPose("botpose_targetspace", false);
}

/**
* Gets the distance from the first visible AprilTag
* @return The distance (in meters) from the AprilTag
*/
public static double getDistanceFromTag() {
Pose3d returnedPose = getBotPoseTargetSpace();

return -returnedPose.getZ();
}

/**
* Gets the latency from the pipeline
* @return The latency
*/
public static double getLatencyPipeline() {
return NetworkTableInstance.getDefault().getTable("limelight").getEntry("tl").getDouble(0.0);
}

/**
* Gets the latency from capturing
* @return The latency
*/
public static double getLatencyCapture() {
return NetworkTableInstance.getDefault().getTable("limelight").getEntry("cl").getDouble(0.0);
}
}
2 changes: 1 addition & 1 deletion src/test/java/frc/robot/subsystems/TestSubsystem.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public void pass() {

@Test
public void fail() {
int x = 5;
int x = 6;
int y = 4;
assertEquals(10, x + y);
}
Expand Down

0 comments on commit 2088a4e

Please sign in to comment.