Skip to content

Commit ddadbdf

Browse files
authored
made vision based off of on season, and reviewed to ensure understanding of it🦟™️ (#17)
1 parent e07710e commit ddadbdf

File tree

3 files changed

+226
-4
lines changed

3 files changed

+226
-4
lines changed

src/main/java/frc/robot/Constants.java

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,21 +247,69 @@ public static class constElevator {
247247
}
248248

249249
public static class constVision {
250+
public static final String[] LIMELIGHT_NAMES = new String[] { "limelight-right", "limelight-left",
251+
"limelight-back" };
252+
250253
/**
251254
* <p>
252255
* Pose estimator standard deviation for vision data
253256
* <p>
254257
* <b>Units:</b> Meters
255258
*/
256-
public static final double STD_DEVS_POS = 0.7;
257259

260+
public static final double STD_DEVS_POS = 0.7;
258261
/**
259262
* <p>
260263
* Pose estimator standard deviation for vision data
261264
* </p>
262265
* <b>Units:</b> Radians
263266
*/
267+
264268
public static final double STD_DEVS_HEADING = 9999999;
265269

270+
/**
271+
* <p>
272+
* Pose estimator standard deviation for vision data
273+
* </p>
274+
* <b>Units:</b> Meters
275+
*/
276+
public static final double MEGA_TAG1_STD_DEVS_POSITION = .3;
277+
278+
public static final double MEGA_TAG1_STD_DEVS_HEADING = .1;
279+
/**
280+
* <p>
281+
* Maximum rate of rotation before we begin rejecting pose updates
282+
* </p>
283+
*/
284+
public static final AngularVelocity MAX_ANGULAR_VELOCITY = Units.DegreesPerSecond.of(720);
285+
286+
/**
287+
* The area that one tag (if its the only tag in the update) needs to exceed
288+
* before being accepted
289+
*/
290+
public static final double AREA_THRESHOLD_FRONT = 0.1;
291+
public static final double AREA_THRESHOLD_BACK = 0.05;
292+
293+
// The below values are accounted for in the limelight interface, NOT in code
294+
public static class LIMELIGHT_RIGHT {
295+
public static final Distance LL_FORWARD = Units.Meters.of(0.269494);
296+
public static final Distance LL_RIGHT = Units.Meters.of(0.307594);
297+
public static final Distance LL_UP = Units.Meters.of(0.211328);
298+
299+
public static final Angle LL_ROLL = Units.Degrees.of(180);
300+
public static final Angle LL_PITCH = Units.Degrees.of(23.17);
301+
public static final Angle LL_YAW = Units.Degrees.of(51.25);
302+
}
303+
304+
public static class LIMELIGHT_LEFT {
305+
public static final Distance LL_FORWARD = Units.Meters.of(0.269494);
306+
public static final Distance LL_RIGHT = Units.Meters.of(-0.307594);
307+
public static final Distance LL_UP = Units.Meters.of(0.211328);
308+
309+
public static final Angle LL_ROLL = Units.Degrees.of(180);
310+
public static final Angle LL_PITCH = Units.Degrees.of(23.17);
311+
public static final Angle LL_YAW = Units.Degrees.of(-51.25);
312+
313+
}
266314
}
267315
}

src/main/java/frc/robot/subsystems/StateMachine.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66

77
import edu.wpi.first.epilogue.Logged;
88
import edu.wpi.first.epilogue.NotLogged;
9-
import edu.wpi.first.wpilibj.RobotState;
109
import edu.wpi.first.wpilibj2.command.Command;
11-
import edu.wpi.first.wpilibj2.command.Command.*;
1210
import edu.wpi.first.wpilibj2.command.Commands;
1311
import edu.wpi.first.wpilibj2.command.SubsystemBase;
1412
import frc.robot.commands.States.*;
@@ -20,7 +18,6 @@
2018
import frc.robot.commands.States.prep_coral.*;
2119
import frc.robot.commands.States.scoring.*;
2220
import frc.robot.commands.States.second_scoring_element.*;
23-
import frc.robot.subsystems.*;
2421

2522
@Logged
2623
public class StateMachine extends SubsystemBase {
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
// Copyright (c) FIRST and other WPILib contributors.
2+
// Open Source Software; you can modify and/or share it under the terms of
3+
// the WPILib BSD license file in the root directory of this project.
4+
5+
package frc.robot.subsystems;
6+
7+
import com.frcteam3255.utils.LimelightHelpers;
8+
import com.frcteam3255.utils.LimelightHelpers.PoseEstimate;
9+
import java.util.Optional;
10+
11+
import edu.wpi.first.epilogue.Logged;
12+
import edu.wpi.first.epilogue.NotLogged;
13+
import edu.wpi.first.math.geometry.Pose2d;
14+
import edu.wpi.first.units.measure.AngularVelocity;
15+
16+
import edu.wpi.first.wpilibj2.command.SubsystemBase;
17+
import frc.robot.Constants.constVision;
18+
19+
@Logged
20+
public class Vision extends SubsystemBase {
21+
PoseEstimate lastEstimateRight = new PoseEstimate();
22+
PoseEstimate lastEstimateLeft = new PoseEstimate();
23+
PoseEstimate lastEstimateBack = new PoseEstimate();
24+
25+
// Not logged, as they turn to false immediately after being read
26+
@NotLogged
27+
boolean newRightEstimate = false;
28+
@NotLogged
29+
boolean newLeftEstimate = false;
30+
@NotLogged
31+
boolean newBackEstimate = false;
32+
33+
Pose2d rightPose = new Pose2d();
34+
Pose2d leftPose = new Pose2d();
35+
Pose2d backPose = new Pose2d();
36+
37+
private boolean useMegaTag2 = false;
38+
39+
public Vision() {
40+
}
41+
42+
public PoseEstimate[] getLastPoseEstimates() {
43+
return new PoseEstimate[] { lastEstimateRight, lastEstimateLeft, lastEstimateBack };
44+
}
45+
46+
public void setMegaTag2(boolean useMegaTag2) {
47+
this.useMegaTag2 = useMegaTag2;
48+
}
49+
50+
/**
51+
* Determines if a given pose estimate should be rejected.
52+
*
53+
*
54+
* @param poseEstimate The pose estimate to check
55+
* @param gyroRate The current rate of rotation observed by our gyro.
56+
*
57+
* @return True if the estimate should be rejected
58+
*/
59+
60+
public boolean rejectUpdate(PoseEstimate poseEstimate, AngularVelocity gyroRate, double areaThreshold) {
61+
// Angular velocity is too high to have accurate vision
62+
if (gyroRate.compareTo(constVision.MAX_ANGULAR_VELOCITY) > 0) {
63+
return true;
64+
}
65+
66+
// No tags :<
67+
if (poseEstimate.tagCount == 0) {
68+
return true;
69+
}
70+
71+
// 1 Tag with a large area
72+
if (poseEstimate.tagCount == 1 && poseEstimate.avgTagArea > areaThreshold) {
73+
return false;
74+
// 2 tags or more
75+
} else if (poseEstimate.tagCount > 1) {
76+
return false;
77+
}
78+
79+
return true;
80+
}
81+
82+
/**
83+
* Updates the current pose estimates for the left and right of the robot using
84+
* data from Limelight cameras.
85+
*
86+
* @param gyroRate The current angular velocity of the robot, used to validate
87+
* the pose estimates.
88+
*
89+
* This method retrieves pose estimates from two Limelight
90+
* cameras (left and right) and updates the
91+
* corresponding pose estimates if they are valid. The method
92+
* supports two modes of operation:
93+
* one using MegaTag2 and one without. The appropriate pose
94+
* estimate retrieval method is chosen
95+
* based on the value of the `useMegaTag2` flag.
96+
*
97+
* If the retrieved pose estimates are valid and not rejected
98+
* based on the current angular velocity,
99+
* the method updates the last known estimates and sets flags
100+
* indicating new estimates are available.
101+
*/
102+
public void setCurrentEstimates(AngularVelocity gyroRate) {
103+
PoseEstimate currentEstimateRight = new PoseEstimate();
104+
PoseEstimate currentEstimateLeft = new PoseEstimate();
105+
PoseEstimate currentEstimateBack = new PoseEstimate();
106+
107+
if (useMegaTag2) {
108+
currentEstimateRight = LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2(constVision.LIMELIGHT_NAMES[0]);
109+
currentEstimateLeft = LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2(constVision.LIMELIGHT_NAMES[1]);
110+
currentEstimateBack = LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2(constVision.LIMELIGHT_NAMES[2]);
111+
} else {
112+
currentEstimateRight = LimelightHelpers.getBotPoseEstimate_wpiBlue(constVision.LIMELIGHT_NAMES[0]);
113+
currentEstimateLeft = LimelightHelpers.getBotPoseEstimate_wpiBlue(constVision.LIMELIGHT_NAMES[1]);
114+
currentEstimateBack = LimelightHelpers.getBotPoseEstimate_wpiBlue(constVision.LIMELIGHT_NAMES[2]);
115+
}
116+
117+
if (currentEstimateRight != null
118+
&& !rejectUpdate(currentEstimateRight, gyroRate, constVision.AREA_THRESHOLD_FRONT)) {
119+
lastEstimateRight = currentEstimateRight;
120+
rightPose = currentEstimateRight.pose;
121+
newRightEstimate = true;
122+
}
123+
if (currentEstimateLeft != null && !rejectUpdate(currentEstimateLeft, gyroRate, constVision.AREA_THRESHOLD_FRONT)) {
124+
lastEstimateLeft = currentEstimateLeft;
125+
leftPose = currentEstimateLeft.pose;
126+
newLeftEstimate = true;
127+
}
128+
if (currentEstimateBack != null && !rejectUpdate(currentEstimateBack, gyroRate, constVision.AREA_THRESHOLD_BACK)) {
129+
lastEstimateBack = currentEstimateBack;
130+
backPose = currentEstimateBack.pose;
131+
newBackEstimate = true;
132+
}
133+
}
134+
135+
public Optional<PoseEstimate> determinePoseEstimate(AngularVelocity gyroRate) {
136+
setCurrentEstimates(gyroRate);
137+
138+
// No valid pose estimates :(
139+
if (!newRightEstimate && !newLeftEstimate && !newBackEstimate) {
140+
return Optional.empty();
141+
142+
} else if (newRightEstimate && !newLeftEstimate && !newBackEstimate) {
143+
// One valid pose estimate (right)
144+
newRightEstimate = false;
145+
return Optional.of(lastEstimateRight);
146+
147+
} else if (!newRightEstimate && newLeftEstimate && !newBackEstimate) {
148+
// One valid pose estimate (left)
149+
newLeftEstimate = false;
150+
return Optional.of(lastEstimateLeft);
151+
152+
} else if (!newRightEstimate && !newLeftEstimate && newBackEstimate) {
153+
// One valid pose estimate (back)
154+
newLeftEstimate = false;
155+
return Optional.of(lastEstimateBack);
156+
157+
} else {
158+
// More than one valid pose estimate, use the closest one
159+
newRightEstimate = false;
160+
newLeftEstimate = false;
161+
newBackEstimate = false;
162+
if (lastEstimateRight.avgTagDist < lastEstimateLeft.avgTagDist
163+
&& lastEstimateRight.avgTagDist < lastEstimateBack.avgTagDist) {
164+
return Optional.of(lastEstimateRight);
165+
} else if (lastEstimateLeft.avgTagDist < lastEstimateRight.avgTagDist
166+
&& lastEstimateLeft.avgTagDist < lastEstimateBack.avgTagDist) {
167+
return Optional.of(lastEstimateLeft);
168+
} else {
169+
return Optional.of(lastEstimateBack);
170+
}
171+
}
172+
}
173+
174+
@Override
175+
public void periodic() {
176+
}
177+
}

0 commit comments

Comments
 (0)