Skip to content

Commit 6c8b04a

Browse files
committed
made AlignCommand more explanable
1 parent a5d9849 commit 6c8b04a

File tree

3 files changed

+333
-122
lines changed

3 files changed

+333
-122
lines changed

src/main/java/frc/robot/Robot.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
package frc.robot;
66

77
import static frc.robot.Constants.RobotConstants.*;
8+
import static frc.robot.subsystems.PoseEstimationSubsystem.*;
89

910
import java.util.Map;
1011

1112
import org.littletonrobotics.urcl.URCL;
1213
import org.photonvision.PhotonCamera;
1314

14-
import edu.wpi.first.math.geometry.Pose2d;
1515
import edu.wpi.first.math.geometry.Rotation2d;
1616
import edu.wpi.first.math.geometry.Transform2d;
1717
import edu.wpi.first.wpilibj.DataLogManager;
@@ -40,10 +40,10 @@ public class Robot extends TimedRobot {
4040
private final PowerDistribution m_pdh = new PowerDistribution();
4141
PhotonCamera m_camera1 = RobotBase.isSimulation()
4242
? new PhotonCameraSimulator("Camera1", kRobotToCamera1, m_driveSubsystem,
43-
new Pose2d(1, 1, Rotation2d.fromDegrees(0)),
43+
pose(1, 1, 0),
4444
0.01, 3,
4545
0.1)
46-
: new PhotonCamera("Cool camera"); // TODO: Check the camera name
46+
: new PhotonCamera("Cool camera");
4747
private final PoseEstimationSubsystem m_poseEstimationSubystem = new PoseEstimationSubsystem(m_driveSubsystem,
4848
m_camera1);
4949

@@ -60,17 +60,14 @@ public Robot() {
6060
bindDriveControls();
6161
}
6262

63-
public static Pose2d pose(double x, double y, double yawInDegrees) {
64-
return new Pose2d(x, y, Rotation2d.fromDegrees(yawInDegrees));
65-
}
66-
6763
public void bindDriveControls() {
6864
m_driveSubsystem.setDefaultCommand(
6965
m_driveSubsystem.driveCommand(
7066
() -> -m_driverController.getLeftY(),
7167
() -> -m_driverController.getLeftX(),
7268
() -> m_driverController.getR2Axis() - m_driverController.getL2Axis(),
7369
m_driverController.getHID()::getSquareButton));
70+
7471
double distanceTolerance = 0.05;
7572
double angleTolerance = 5;
7673
m_driverController.button(Button.kSquare) // home
@@ -86,12 +83,22 @@ public void bindDriveControls() {
8683
new DriveCommand(
8784
m_driveSubsystem, pose(2, 0, 0), distanceTolerance, angleTolerance));
8885

89-
Transform2d robotToTarget = new Transform2d(1.5, 0, Rotation2d.fromDegrees(180));
86+
double angleOfCoverageInDegrees = 90;
87+
double distanceThresholdInMeters = 4;
9088
m_driverController.button(Button.kTriangle)
89+
.whileTrue(
90+
AlignCommand.turnToClosestTag(
91+
m_driveSubsystem, m_poseEstimationSubystem, angleOfCoverageInDegrees,
92+
distanceThresholdInMeters,
93+
distanceTolerance, angleTolerance));
94+
95+
Transform2d robotToTarget = new Transform2d(1.5, 0, Rotation2d.fromDegrees(180));
96+
m_driverController.button(Button.kLeftBumper)
9197
.whileTrue(
9298
AlignCommand.moveToClosestTag(
93-
m_driveSubsystem, m_poseEstimationSubystem, 90, 3, robotToTarget,
94-
.2, 10));
99+
m_driveSubsystem, m_poseEstimationSubystem, angleOfCoverageInDegrees,
100+
distanceThresholdInMeters, robotToTarget,
101+
distanceTolerance, angleTolerance));
95102
}
96103

97104
@Override
Lines changed: 127 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
package frc.robot.commands;
22

3-
import static frc.robot.Constants.*;
4-
5-
import java.util.Map;
6-
import java.util.Map.Entry;
7-
import java.util.Optional;
83
import java.util.function.Supplier;
94

105
import edu.wpi.first.math.geometry.Pose2d;
11-
import edu.wpi.first.math.geometry.Rotation2d;
126
import edu.wpi.first.math.geometry.Transform2d;
137
import edu.wpi.first.math.geometry.Translation2d;
148
import edu.wpi.first.wpilibj2.command.Command;
@@ -35,14 +29,102 @@ public class AlignCommand extends Command {
3529
* @return a {@code Commmand} for moving the robot to the specified
3630
* target
3731
*/
38-
public static DriveCommand moveTo(DriveSubsystem driveSubsystem,
39-
PoseEstimationSubsystem poseEstimationSubsystem,
32+
public static DriveCommand moveTo(DriveSubsystem driveSubsystem, PoseEstimationSubsystem poseEstimationSubsystem,
4033
Pose2d targetPose, double distanceTolerance, double angleTolerance) {
41-
return new DriveCommand(driveSubsystem, () -> poseEstimationSubsystem.getPose(),
42-
() -> targetPose,
34+
return moveTo(driveSubsystem, poseEstimationSubsystem, () -> targetPose, distanceTolerance, angleTolerance);
35+
}
36+
37+
/**
38+
* Constructs a {@code DriveCommand} for moving the robot to the specified
39+
* target.
40+
*
41+
* @param driveSubsystem the {@code DriveSubsystem} to use
42+
* @param poseEstimationSubsystem the {@code PoseEstimationSubsystem} to use
43+
* @param targetPoseSupplier a {@code Supplier<Pose2d>} that provides the
44+
* {@code Pose2d} of the target.
45+
* This is used at the commencement of the {@code DriveCommand} (i.e.,
46+
* when the scheduler begins to periodically execute the
47+
* {@code DriveCommand})
48+
* @param distanceTolerance the distance error in meters which is tolerable
49+
* @param angleTolerance the angle error in degrees which is tolerable
50+
* @return a {@code Commmand} for moving the robot to the specified
51+
* target
52+
*/
53+
public static DriveCommand moveTo(DriveSubsystem driveSubsystem, PoseEstimationSubsystem poseEstimationSubsystem,
54+
Supplier<Pose2d> targetPoseSupplier, double distanceTolerance, double angleTolerance) {
55+
return new DriveCommand(driveSubsystem, () -> poseEstimationSubsystem.getEstimatedPose(),
56+
targetPoseSupplier,
4357
distanceTolerance, angleTolerance);
4458
}
4559

60+
/**
61+
* Constructs a {@code DriveCommand} for turning the robot to the specified
62+
* target.
63+
*
64+
* @param driveSubsystem the {@code DriveSubsystem} to use
65+
* @param poseEstimationSubsystem the {@code PoseEstimationSubsystem} to use
66+
* @param targetPose the {@code Pose2d} of the target
67+
* @param distanceTolerance the distance error in meters which is tolerable
68+
* @param angleTolerance the angle error in degrees which is tolerable
69+
* @return a {@code Commmand} for turning the robot to the specified
70+
* target
71+
*/
72+
public static DriveCommand turnTo(DriveSubsystem driveSubsystem, PoseEstimationSubsystem poseEstimationSubsystem,
73+
Pose2d targetPose, double distanceTolerance, double angleTolerance) {
74+
return turnTo(driveSubsystem, poseEstimationSubsystem, () -> targetPose, distanceTolerance, angleTolerance);
75+
}
76+
77+
/**
78+
* Constructs a {@code DriveCommand} for turning the robot to the specified
79+
* target.
80+
*
81+
* @param driveSubsystem the {@code DriveSubsystem} to use
82+
* @param poseEstimationSubsystem the {@code PoseEstimationSubsystem} to use
83+
* @param targetPoseSupplier a {@code Supplier<Pose2d>} that provides the
84+
* {@code Pose2d} of the target.
85+
* This is used at the commencement of the {@code DriveCommand} (i.e.,
86+
* when the scheduler begins to periodically execute the
87+
* {@code DriveCommand})
88+
* @param distanceTolerance the distance error in meters which is tolerable
89+
* @param angleTolerance the angle error in degrees which is tolerable
90+
* @return a {@code Commmand} for turning the robot to the specified
91+
* target
92+
*/
93+
public static DriveCommand turnTo(DriveSubsystem driveSubsystem, PoseEstimationSubsystem poseEstimationSubsystem,
94+
Supplier<Pose2d> targetPoseSupplier, double distanceTolerance, double angleTolerance) {
95+
return new DriveCommand(driveSubsystem, () -> poseEstimationSubsystem.getEstimatedPose(),
96+
() -> {
97+
var transform = new Transform2d(0, 0,
98+
poseEstimationSubsystem.angularDisplacement(targetPoseSupplier.get()));
99+
return poseEstimationSubsystem.getEstimatedPose().plus(transform);
100+
},
101+
distanceTolerance, angleTolerance);
102+
}
103+
104+
/**
105+
* Constructs a {@code DriveCommand} for moving the robot toward the specified
106+
* target position while ensuring that the robot is away from the target by the
107+
* specified distance.
108+
*
109+
* @param driveSubsystem the {@code DriveSubsystem} to use
110+
* @param poseEstimaitonSubsystem the {@code PoseEstimationSubsystem} to use
111+
* @param targetPosition a {@code Translation2d} (i.e., the position) of the
112+
* target.
113+
* @param distanceToTarget the desired distance between the robot and the
114+
* target position
115+
* @param distanceTolerance the distance error in meters which is tolerable
116+
* @param angleTolerance the angle error in degrees which is tolerable
117+
* @return a {@code Commmand} for turning the robot to the specified target
118+
* position
119+
*/
120+
public static DriveCommand moveToward(DriveSubsystem driveSubsystem,
121+
PoseEstimationSubsystem poseEstimaitonSubsystem, Translation2d targetPosition, double distanceToTarget,
122+
double distanceTolerance, double angleTolerance) {
123+
return moveToward(
124+
driveSubsystem, poseEstimaitonSubsystem, () -> targetPosition, distanceToTarget, distanceTolerance,
125+
angleTolerance);
126+
}
127+
46128
/**
47129
* Constructs a {@code DriveCommand} for moving the robot toward the specified
48130
* target position while ensuring that the robot is away from the target by the
@@ -63,20 +145,20 @@ public static DriveCommand moveTo(DriveSubsystem driveSubsystem,
63145
* position
64146
*/
65147
public static DriveCommand moveToward(DriveSubsystem driveSubsystem,
66-
PoseEstimationSubsystem poseEstimaitonSubsystem,
67-
Supplier<Translation2d> targetPositionSupplier,
68-
double distanceToTarget,
69-
double distanceTolerance,
70-
double angleTolerance) {
71-
Supplier<Pose2d> poseSupplier = () -> poseEstimaitonSubsystem.getPose();
148+
PoseEstimationSubsystem poseEstimaitonSubsystem, Supplier<Translation2d> targetPositionSupplier,
149+
double distanceToTarget, double distanceTolerance, double angleTolerance) {
150+
Supplier<Pose2d> poseSupplier = () -> poseEstimaitonSubsystem.getEstimatedPose();
72151
return new DriveCommand(driveSubsystem, poseSupplier,
73-
() -> poseSupplier.get()
74-
.plus(transformationToward(targetPositionSupplier.get(), poseSupplier.get(), distanceToTarget)),
152+
() -> {
153+
var transform = poseEstimaitonSubsystem
154+
.transformationToward(targetPositionSupplier.get(), distanceToTarget);
155+
return poseSupplier.get().plus(transform);
156+
},
75157
distanceTolerance, angleTolerance);
76158
}
77159

78160
/**
79-
* Constructs a {@code DriveCommand} for moving the robot to the specified
161+
* Constructs a {@code DriveCommand} for turning the robot to the specified
80162
* target.
81163
*
82164
* @param driveSubsystem the {@code DriveSubsystem} to use
@@ -85,112 +167,46 @@ public static DriveCommand moveToward(DriveSubsystem driveSubsystem,
85167
* which {@code AprilTag}s are considered (maximum: 180)
86168
* @param distanceThresholdInMeters the maximum distance (in meters) within
87169
* which {@code AprilTag}s are considered
88-
* @param robotToTarget the {@code Pose2d} of the target relative to the
89-
* {@code Pose2d} of the robot for the {@code DriveCommand} to finish
90170
* @param distanceTolerance the distance error in meters which is tolerable
91171
* @param angleTolerance the angle error in degrees which is tolerable
92-
* @return a {@code Commmand} for moving the robot to the specified
172+
* @return a {@code Commmand} for turning the robot to the specified
93173
* target
94174
*/
95-
public static DriveCommand moveToClosestTag(DriveSubsystem driveSubsystem,
175+
public static DriveCommand turnToClosestTag(DriveSubsystem driveSubsystem,
96176
PoseEstimationSubsystem poseEstimationSubsystem, double angleOfCoverageInDegrees,
97-
double distanceThresholdInMeters,
98-
Transform2d robotToTarget, double distanceTolerance, double angleTolerance) {
99-
return new DriveCommand(driveSubsystem, () -> poseEstimationSubsystem.getPose(),
100-
() -> kFieldLayout
101-
.getTagPose(
102-
closestTagID(
103-
poseEstimationSubsystem.getPose(), angleOfCoverageInDegrees,
104-
distanceThresholdInMeters))
105-
.get()
106-
.toPose2d()
107-
.transformBy(robotToTarget),
108-
distanceTolerance, angleTolerance);
109-
}
110-
111-
/**
112-
* Returns the transformation needed for the robot to face toward the specified
113-
* target position and remain the specified distance away fron the target
114-
* position.
115-
*
116-
* @param targetPosition the target position whose x and y-coordinate values
117-
* are in meters
118-
* @param distanceToTarget the desired distance in meters to the target
119-
* @return the transformation needed for the robot to face toward the specified
120-
* target position and remain the specified distance away fron the
121-
* target position; {@code null} if it has not been
122-
* possible to reliably estimate the pose of the robot
123-
*/
124-
public static Transform2d transformationToward(Translation2d targetPosition, Pose2d currentPose,
125-
double distanceToTarget) {
126-
Translation2d diff = targetPosition.minus(currentPose.getTranslation());
127-
if (diff.getNorm() == 0)
128-
return null;
129-
var targetPose = new Pose2d(
130-
currentPose.getTranslation().plus(diff.times(1 - distanceToTarget / diff.getNorm())),
131-
diff.getAngle());
132-
return targetPose.minus(currentPose);
177+
double distanceThresholdInMeters, double distanceTolerance, double angleTolerance) {
178+
return turnTo(
179+
driveSubsystem, poseEstimationSubsystem,
180+
() -> poseEstimationSubsystem.closestTagPose(angleOfCoverageInDegrees, distanceThresholdInMeters),
181+
distanceThresholdInMeters, angleTolerance);
133182
}
134183

135184
/**
136-
* Determines the ID of the {@code AprilTag} that is closest to the specified
137-
* {@code Pose2d} ({@code null} if no such {@code AprilTag}).
185+
* Constructs a {@code DriveCommand} for moving the robot to the specified
186+
* target.
138187
*
139-
* @param pose a {@code Pose2d}
188+
* @param driveSubsystem the {@code DriveSubsystem} to use
189+
* @param poseEstimationSubsystem the {@code PoseEstimationSubsystem} to use
140190
* @param angleOfCoverageInDegrees the angular coverage (in degrees) within
141191
* which {@code AprilTag}s are considered (maximum: 180)
142192
* @param distanceThresholdInMeters the maximum distance (in meters) within
143193
* which {@code AprilTag}s are considered
144-
* @return the ID of the {@code AprilTag} that is closest to the specified
145-
* {@code Pose2d} ({@code null} if no such {@code AprilTag})
146-
*/
147-
public static Integer closestTagID(Pose2d pose, double angleOfCoverageInDegrees, double distanceThresholdInMeters) {
148-
var s = kFieldLayout.getTags().stream()
149-
// consider only the tags facing toward the robot
150-
.filter(
151-
t -> Math.abs(
152-
t.pose.getTranslation().toTranslation2d().minus(pose.getTranslation()).getAngle()
153-
.minus(t.pose.toPose2d().getRotation()).getDegrees()) > 90)
154-
.filter( // consider only the tags within the angle of coverage
155-
t -> Math.abs(
156-
angularDisplacement(pose, t.pose.toPose2d()).getDegrees()) < angleOfCoverageInDegrees)
157-
.map(t -> Map.entry(t.ID, Math.abs(translationalDisplacement(pose, t.pose.toPose2d())))) // distance
158-
.filter(t -> t.getValue() < distanceThresholdInMeters); // only tags sufficently close
159-
Optional<Entry<Integer, Double>> closest = s.reduce((e1, e2) -> e1.getValue() < e2.getValue() ? e1 : e2);
160-
if (closest.isPresent()) {
161-
return closest.get().getKey();
162-
} else
163-
return null;
164-
}
165-
166-
/**
167-
* Calculates the angular displacement given the initial and last
168-
* {@code Pose2d}s.
169-
*
170-
* @param initial the initial {@code Pose2d}
171-
* @param last the last {@code Pose2d}
172-
* @return the angular displacement given the initial and last
173-
* {@code Pose2d}s
174-
*/
175-
public static Rotation2d angularDisplacement(Pose2d initial, Pose2d last) {
176-
var t = last.getTranslation().minus(initial.getTranslation());
177-
return t.getAngle().minus(initial.getRotation());
178-
}
179-
180-
/**
181-
* Calculates the translational displacement given the initial and last
182-
* {@code Pose2d}s.
183-
*
184-
* @param initial the initial {@code Pose2d}
185-
* @param last the last {@code Pose2d}
186-
* @return the translational displacement given the initial and last
187-
* {@code Pose2d}s
194+
* @param robotToTarget the {@code Pose2d} of the target relative to the
195+
* {@code Pose2d} of the robot for the {@code DriveCommand} to finish
196+
* @param distanceTolerance the distance error in meters which is tolerable
197+
* @param angleTolerance the angle error in degrees which is tolerable
198+
* @return a {@code Commmand} for moving the robot to the specified
199+
* target
188200
*/
189-
public static double translationalDisplacement(Pose2d initial, Pose2d last) {
190-
var t = last.getTranslation().minus(initial.getTranslation());
191-
return Math.abs(t.getAngle().minus(initial.getRotation()).getDegrees()) > 90
192-
? -t.getNorm()
193-
: t.getNorm();
201+
public static DriveCommand moveToClosestTag(DriveSubsystem driveSubsystem,
202+
PoseEstimationSubsystem poseEstimationSubsystem, double angleOfCoverageInDegrees,
203+
double distanceThresholdInMeters, Transform2d robotToTarget, double distanceTolerance,
204+
double angleTolerance) {
205+
return moveTo(
206+
driveSubsystem, poseEstimationSubsystem,
207+
() -> poseEstimationSubsystem.closestTagPose(angleOfCoverageInDegrees, distanceThresholdInMeters)
208+
.plus(robotToTarget),
209+
distanceTolerance, angleTolerance);
194210
}
195211

196212
}

0 commit comments

Comments
 (0)