Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pose estimation v2 #154

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
ac0bd5c
Switch from 2910 to WPILib geometry classes
KangarooKoala Mar 26, 2022
8b6db4d
Pose frames of reference
KangarooKoala Mar 29, 2022
3e1d680
Merge branch 'main' of https://github.com/robototes/RapidReact2022 in…
KangarooKoala Mar 29, 2022
259913c
Added correction for different start poses
KangarooKoala Mar 29, 2022
175f84a
Moved constants to appropriate subsystems
KangarooKoala Mar 30, 2022
39cfea5
Merge branch 'main' of https://github.com/robototes/RapidReact2022 in…
KangarooKoala Apr 1, 2022
b986b61
Merge branch 'main' of https://github.com/robototes/RapidReact2022 in…
KangarooKoala Apr 2, 2022
2f64860
Merge branch 'main' of https://github.com/robototes/RapidReact2022 in…
KangarooKoala Apr 5, 2022
c5b15bc
Merge branch 'main' of https://github.com/robototes/RapidReact2022 in…
KangarooKoala Apr 6, 2022
9b19933
Merge branch 'main' of https://github.com/robototes/RapidReact2022 in…
KangarooKoala Apr 6, 2022
8f09430
Merge branch 'main' of https://github.com/robototes/RapidReact2022 in…
KangarooKoala Apr 11, 2022
a97fe79
Merge branch 'main' of https://github.com/robototes/RapidReact2022 in…
KangarooKoala Apr 11, 2022
09c4529
Merge branch 'main' of https://github.com/robototes/RapidReact2022 in…
KangarooKoala Apr 20, 2022
ce61229
Merge branch 'main' of https://github.com/robototes/RapidReact2022 in…
KangarooKoala May 1, 2022
fc46063
Add VisionUtil
KangarooKoala May 4, 2022
dd91319
Misc. fixes and clean-ups
KangarooKoala May 4, 2022
bb0c181
Merge branch 'main' of https://github.com/robototes/RapidReact2022 in…
KangarooKoala May 13, 2022
12a52a7
Improve doc comments and correct naming
KangarooKoala May 13, 2022
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
4 changes: 4 additions & 0 deletions src/main/java/frc/team2412/robot/Robot.java
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@ public void autonomousInit() {
subsystems.drivebaseSubsystem.resetPose(autonomousChooser.getStartPose());
}

if (subsystems.targetLocalizer != null) {
subsystems.targetLocalizer.resetPoseFromAutoStartPose(autonomousChooser);
}

if (subsystems.shooterSubsystem != null) {
new ShooterResetEncodersCommand(subsystems.shooterSubsystem).schedule();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.google.errorprone.annotations.concurrent.GuardedBy;
import com.swervedrivespecialties.swervelib.SwerveModule;
import edu.wpi.first.math.geometry.Pose2d;
import edu.wpi.first.math.geometry.Rotation2d;
import edu.wpi.first.math.geometry.Translation2d;
import edu.wpi.first.math.kinematics.ChassisSpeeds;
import edu.wpi.first.math.kinematics.SwerveDriveKinematics;
Expand Down Expand Up @@ -232,9 +233,14 @@ public Vector2 getGyroscopeXY() {
return Vector2.ZERO;
}

public Rotation2 getGyroscopeUnadjustedAngle() {
/**
* Returns the unadjusted gyroscope angle.
*
* @return Unadjusted gyroscope angle (yaw, positive rotation is clockwise)
*/
public Rotation2d getGyroscopeUnadjustedAngle() {
synchronized (sensorLock) {
return gyroscope.getUnadjustedAngle();
return Rotation2d.fromDegrees(gyroscope.getUnadjustedAngle().toDegrees());
TAKBS2412 marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
221 changes: 115 additions & 106 deletions src/main/java/frc/team2412/robot/subsystem/TargetLocalizer.java
Original file line number Diff line number Diff line change
@@ -1,40 +1,58 @@
package frc.team2412.robot.subsystem;

import org.frcteam2910.common.math.RigidTransform2;
import org.frcteam2910.common.math.Rotation2;
import org.frcteam2910.common.math.Vector2;

import frc.team2412.robot.Robot;

import frc.team2412.robot.util.GeoConvertor;
import frc.team2412.robot.util.TimeBasedMedianFilter;
import frc.team2412.robot.util.autonomous.AutonomousChooser;

import static frc.team2412.robot.subsystem.TargetLocalizer.LocalizerConstants.*;

import edu.wpi.first.math.geometry.Pose2d;
import edu.wpi.first.math.geometry.Rotation2d;
import edu.wpi.first.math.geometry.Translation2d;

/**
* Class that combines sensor data from multiple subsystems. <br>
*
* <p>
* Field-centric pose frame of reference:
* <ul>
* <li>Units are inches</li>
* <li>Origin is right corner of alliance wall</li>
* <li>Positive X axis points away from alliance wall</li>
* <li>Positive Y axis points left from alliance wall</li>
* <li>0 rotation points away from alliance wall</li>
* <li>Positive rotation is counterclockwise</li>
* </ul>
* </p>
*/
public class TargetLocalizer {
public static class LocalizerConstants {
// TODO tune these more
public static final double TURRET_LATERAL_FF = 0, TURRET_ANGULAR_FF = 4, TURRET_DEPTH_FF = 0;
// Seconds, placeholder duration
public static final double FILTER_TIME = 1;
// Angles are in degrees
// Positive is clockwise
public static final double STARTING_TURRET_ANGLE = 0;
// Dimensions are in inches
public static final double VISION_DEFAULT_DISTANCE = 118;
// Estimated, negative because limelight is in back of turret
public static final double LIMELIGHT_TO_TURRET_CENTER_DISTANCE = -7;
public static final Vector2 ROBOT_CENTRIC_TURRET_CENTER = new Vector2(3.93, -4);
public static final double TURRET_CENTER_TO_LIMELIGHT_DISTANCE = -7;
public static final Translation2d ROBOT_CENTRIC_TURRET_CENTER = new Translation2d(3.93, -4);
public static final Translation2d FIELD_CENTRIC_HUB_CENTER = new Translation2d(27 * 12, 13.5 * 12);
}

private final DrivebaseSubsystem drivebaseSubsystem;
private final ShooterSubsystem shooterSubsystem;
private final ShooterVisionSubsystem shooterVisionSubsystem;
private final TimeBasedMedianFilter distanceFilter;
private final Rotation2 gyroAdjustmentAngle;
private final RigidTransform2 startingPose;
private Pose2d startingPose;
private Rotation2d gyroAdjustmentAngle;

/**
* Creates a new {@link TargetLocalizer}.
* If {@code drivebase} is null, will assume robot is stationary.
* If {@code drivebaseSubsystem} is null, will assume robot is stationary.
*
* @param drivebaseSubsystem
* The drivebase subsystem.
Expand All @@ -49,11 +67,28 @@ public TargetLocalizer(DrivebaseSubsystem drivebaseSubsystem, ShooterSubsystem s
this.shooterSubsystem = shooterSubsystem;
this.shooterVisionSubsystem = visionSubsystem;
this.distanceFilter = new TimeBasedMedianFilter(FILTER_TIME);
// TODO Handle different starting positions
// Also don't forget to convert reference to hub-centric if necessary
this.startingPose = new RigidTransform2(new Vector2(5 * 12, 5 * 12), Rotation2.ZERO);
this.gyroAdjustmentAngle = startingPose.rotation
.rotateBy(drivebaseSubsystem.getGyroscopeUnadjustedAngle().inverse());
resetPose(new Pose2d());
}

/**
* Rests the current pose according to the current auto path.
KangarooKoala marked this conversation as resolved.
Show resolved Hide resolved
*
* @param autoChooser
* The autonomous chooser with the current auto path.
*/
public void resetPoseFromAutoStartPose(AutonomousChooser autoChooser) {
resetPose(autoChooser.getStartPose());
}

/**
* Resets the current pose.
*
* @param newPose
* The new (field-centric) pose.
*/
public void resetPose(Pose2d newPose) {
this.startingPose = newPose;
this.gyroAdjustmentAngle = startingPose.getRotation().minus(getGyroscopeYaw());
}

public double getDistance() {
Expand Down Expand Up @@ -88,8 +123,7 @@ public boolean hasTarget() {
/**
* Returns the yaw (horizontal angle) to the hub.
*
* @return The yaw to the hub (0 is straight ahead, positive is clockwise, units
* are degrees).
* @return The yaw to the hub (0 is straight ahead, positive is clockwise, units are degrees).
*/
public double getVisionYaw() {
return shooterVisionSubsystem.getYaw();
Expand All @@ -98,33 +132,58 @@ public double getVisionYaw() {
/**
* Returns the yaw (horizontal angle) to the target position.
*
* @return The yaw to the hub plus turret angle bias (0 is straight ahead,
* positive is clockwise,
* @return The yaw to the hub plus turret angle bias (0 is straight ahead, positive is clockwise,
* units are degrees).
*/
public double getTargetYaw() {
// return 0;
return getVisionYaw() + shooterSubsystem.getTurretAngleBias();
}

/**
* Returns the gyroscope's yaw.
*
* @return The gyroscope's yaw without the adjustment angle (positive rotation is counterclockwise).
KangarooKoala marked this conversation as resolved.
Show resolved Hide resolved
*/
public Rotation2d getGyroscopeYaw() {
return (drivebaseSubsystem != null) ? drivebaseSubsystem.getGyroscopeUnadjustedAngle().unaryMinus()
: new Rotation2d();
}

/**
* Return the robot's angle relative to the field.
*
* @return The robot angle (0 is straight forward from the driver station,
* positive rotation is
* clockwise).
* @return The robot angle (0 is straight forward from the driver station, positive rotation is
* counterclockwise).
*/
public Rotation2d getFieldCentricRobotAngle() {
return getGyroscopeYaw().rotateBy(gyroAdjustmentAngle);
}

/**
* Returns the turret's angle relative to the field.
*
* @return The turret angle (0 is straight forward from the driver station, positive rotation is
* counterclockwise).
*/
public Rotation2 getFieldCentricRobotAngle() {
return drivebaseSubsystem.getGyroscopeUnadjustedAngle().rotateBy(gyroAdjustmentAngle);
public Rotation2d getFieldCentricTurretAngle() {
return getFieldCentricRobotAngle().rotateBy(getTurretAngle().unaryMinus());
}

/**
* Return the turret's angle.
*
* @return The turret angle (0 is intake side, positive is clockwise).
* @return The turret angle (0 is intake side, positive rotation is clockwise).
*/
public Rotation2 getTurretAngle() {
return Rotation2.fromDegrees(shooterSubsystem.getTurretAngle() + STARTING_TURRET_ANGLE);
public Rotation2d getTurretAngle() {
return Rotation2d.fromDegrees(shooterSubsystem.getTurretAngle() + STARTING_TURRET_ANGLE);
}

public Translation2d getTurretRelativeVelocity() {
return (drivebaseSubsystem != null)
// might need to do inverse
? GeoConvertor.vector2ToTranslation2d(drivebaseSubsystem.getVelocity()).rotateBy(getTurretAngle())
: new Translation2d();
}

/**
Expand All @@ -133,10 +192,7 @@ public Rotation2 getTurretAngle() {
* @return that
*/
public double getLateralVelocity() {
return (drivebaseSubsystem != null)
// might need to do inverse
? drivebaseSubsystem.getVelocity().rotateBy(getTurretAngle()).x
: 0;
return getTurretRelativeVelocity().getX();
}

/**
Expand All @@ -145,10 +201,7 @@ public double getLateralVelocity() {
* @return that
*/
public double getDepthVelocity() {
return (drivebaseSubsystem != null)
// might need to do inverse
? drivebaseSubsystem.getVelocity().rotateBy(getTurretAngle()).y
: 0;
return getTurretRelativeVelocity().getX();
}

public double getAngularVelocity() {
Expand All @@ -173,90 +226,46 @@ public double yawAdjustment() {
}

/**
* Returns the estimated limelight pose according to vision and the gyroscope.
*
* The translation (inches) is relative to the hub, and the rotation is relative
* to straight forward
* from the driver station (Positive rotation is clockwise). If the limelight
* doesn't have a target,
* returns {@link RigidTransform2#ZERO}.
* Returns the estimated limelight pose according to vision and the gyroscope. <br>
*
* For example, returning
* {@code RigidTransform2(Vector2(12, -24), Rotation2.fromDegrees(20))} means
* that, looking out from the driver station, the limelight is one foot to the
* right of and two feet
* in front of the center of the hub and is pointing 20 degrees to the right
* (clockwise).
* <p>
* If the limelight doesn't have a target, returns {@code Pose2d()}.
* </p>
*
* @return The estimated limelight pose according to vision and the gyroscope.
* @return The field-centric estimated limelight pose according to vision and the gyroscope.
*/
public RigidTransform2 getVisionGyroLimelightPose() {
public Pose2d getVisionGyroLimelightPose() {
if (!hasTarget()) {
return RigidTransform2.ZERO;
return new Pose2d();
}
Rotation2 fieldCentricLimelightAngle = getFieldCentricRobotAngle().rotateBy(getTurretAngle());
Rotation2 fieldCentricLimelightToHubAngle = fieldCentricLimelightAngle
.rotateBy(Rotation2.fromDegrees(getVisionYaw()));
Rotation2 fieldCentricHubToLimelightAngle = fieldCentricLimelightToHubAngle
.rotateBy(Rotation2.fromDegrees(180));
Vector2 forwardXTranslation = Vector2.fromAngle(fieldCentricHubToLimelightAngle).scale(getDistance());
Vector2 forwardYTranslation = forwardXTranslation.rotateBy(Rotation2.fromDegrees(90));
return new RigidTransform2(forwardYTranslation, fieldCentricLimelightAngle);
Rotation2d limelightAngle = getFieldCentricTurretAngle();
Rotation2d hubAngle = limelightAngle.rotateBy(Rotation2d.fromDegrees(-getVisionYaw()));
Translation2d limelightToHub = new Translation2d(getDistance(), hubAngle);
Translation2d translation = FIELD_CENTRIC_HUB_CENTER.minus(limelightToHub);
return new Pose2d(translation, limelightAngle);
}

/**
* Returns the estimated robot pose according to vision and the gyroscope.
*
* The translation (inches) is relative to the hub, and the rotation is relative
* to straight forward
* from the drive station (Positive rotation is clockwise). If the limelight
* doesn't have a target,
* returns {@link RigidTransform2#ZERO}.
* Returns the estimated robot pose according to vision and the gyroscope. <br>
*
* For example, returning
* {@code RigidTransform2(Vector2(12, -24), Rotation.fromDegrees(20))} means
* that, looking from the driver station, the center of the robot is one foot to
* the right of and
* two feet in front of the center of the hub and is pointing 20 degrees to the
* right (clockwise).
* <p>
* If the limelight doesn't have a target, returns {@code Pose2d()}.
* </p>
*
* @return The estimated robot pose according to vision and the gyroscope.
* @return The estimated field-centric robot pose according to vision and the gyroscope.
*/
public RigidTransform2 getVisionGyroRobotPose() {
public Pose2d getVisionGyroRobotPose() {
if (!hasTarget()) {
return RigidTransform2.ZERO;
return new Pose2d();
}
Vector2 fieldCentricHubToLimelight = getVisionGyroLimelightPose().translation;
Vector2 robotCentricTurretToLimelight = Vector2.fromAngle(getTurretAngle())
.scale(LIMELIGHT_TO_TURRET_CENTER_DISTANCE);
Vector2 robotCentricLimelightPosition = ROBOT_CENTRIC_TURRET_CENTER.add(robotCentricTurretToLimelight);
Vector2 fieldCentricRobotToLimelight = robotCentricLimelightPosition.rotateBy(getFieldCentricRobotAngle())
.rotateBy(Rotation2.fromDegrees(90));
Vector2 hubToRobot = fieldCentricHubToLimelight.subtract(fieldCentricRobotToLimelight);
return new RigidTransform2(hubToRobot, getFieldCentricRobotAngle());
}

/**
* Returns the estimated robot pose relative to the start according to vision
* and the gyroscope.
*
* The translation (inches) is from the starting position, and the rotation is
* relative to the
* starting rotation (Positive is clockwise). If the limelight doesn't have a
* target, returns
* {@link RigidTransform2#ZERO}.
*
* For example, returning
* {@code RigidTransform2(Vector2(12, -24), Rotation2.fromDegrees(20))} means
* that, looking from the driver station, the robot moved one foot to the right
* and two feet closer,
* and rotated 20 degrees clockwise.
*
* @return The estimated robot pose relative to the start according to vision
* and the gyroscope.
*/
public RigidTransform2 getVisionGyroRobotPoseRelativeToStart() {
return hasTarget() ? getVisionGyroRobotPose().transformBy(startingPose.inverse()) : RigidTransform2.ZERO;
Rotation2d robotAngle = getFieldCentricRobotAngle();
Translation2d limelightTranslation = getVisionGyroLimelightPose().getTranslation();
Translation2d turretToLimelight = new Translation2d(TURRET_CENTER_TO_LIMELIGHT_DISTANCE,
getFieldCentricTurretAngle());
Translation2d robotToTurret = ROBOT_CENTRIC_TURRET_CENTER.rotateBy(new Rotation2d(Math.PI / 2))
.rotateBy(robotAngle);
Translation2d translation = limelightTranslation.minus(robotToTurret.plus(turretToLimelight));
return new Pose2d(translation, robotAngle);
}

public void limelightOn() {
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/frc/team2412/robot/util/GeoConvertor.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,8 @@ public static Rotation2 rotation2dToRotation2(Rotation2d r) {
public static Vector2 translation2dToVector2(Translation2d trans) {
return new Vector2(trans.getX(), trans.getY());
}

public static Translation2d vector2ToTranslation2d(Vector2 vector) {
return new Translation2d(vector.x, vector.y);
}
}