-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPPHolonomicDriveControllerGeoFenced.java
More file actions
266 lines (231 loc) · 10 KB
/
PPHolonomicDriveControllerGeoFenced.java
File metadata and controls
266 lines (231 loc) · 10 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package frc.robot.util;
import java.util.Optional;
import java.util.function.DoubleSupplier;
import java.util.function.Supplier;
import com.pathplanner.lib.config.PIDConstants;
import com.pathplanner.lib.controllers.PathFollowingController;
import com.pathplanner.lib.trajectory.PathPlannerTrajectoryState;
import edu.wpi.first.math.controller.PIDController;
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.wpilibj.smartdashboard.SmartDashboard;
import frc.robot.constants.Constants;
import frc.robot.constants.FieldConstants;
/** Add your docs here. */
public class PPHolonomicDriveControllerGeoFenced implements PathFollowingController
{
private final PIDController xController;
private final PIDController yController;
private final PIDController rotationController;
private Translation2d translationError = new Translation2d();
private boolean isEnabled = true;
private static Supplier<Optional<Rotation2d>> rotationTargetOverride = null;
private static DoubleSupplier xFeedbackOverride = null;
private static DoubleSupplier yFeedbackOverride = null;
private static DoubleSupplier rotFeedbackOverride = null;
private static GeoFenceObject[] fieldGeoFence = FieldConstants.GeoFencing.fieldGeoFence;
private static double robotRadius = FieldConstants.GeoFencing.robotRadiusCircumscribed;
/**
* Constructs a HolonomicDriveController
*
* @param translationConstants PID constants for the translation PID controllers
* @param rotationConstants PID constants for the rotation controller
* @param period Period of the control loop in seconds
*/
public PPHolonomicDriveControllerGeoFenced(PIDConstants translationConstants, PIDConstants rotationConstants, double period)
{
this.xController = new PIDController(translationConstants.kP, translationConstants.kI, translationConstants.kD, period);
this.xController.setIntegratorRange(-translationConstants.iZone, translationConstants.iZone);
this.yController = new PIDController(translationConstants.kP, translationConstants.kI, translationConstants.kD, period);
this.yController.setIntegratorRange(-translationConstants.iZone, translationConstants.iZone);
// Temp rate limit of 0, will be changed in calculate
this.rotationController = new PIDController(rotationConstants.kP, rotationConstants.kI, rotationConstants.kD, period);
this.rotationController.setIntegratorRange(-rotationConstants.iZone, rotationConstants.iZone);
this.rotationController.enableContinuousInput(-Math.PI, Math.PI);
}
/**
* Constructs a HolonomicDriveController
*
* @param translationConstants PID constants for the translation PID controllers
* @param rotationConstants PID constants for the rotation controller
*/
public PPHolonomicDriveControllerGeoFenced(PIDConstants translationConstants, PIDConstants rotationConstants)
{
this(translationConstants, rotationConstants, 0.02);
}
/**
* Enables and disables the controller for troubleshooting. When calculate() is called on a
* disabled controller, only feedforward values are returned.
*
* @param enabled If the controller is enabled or not
*/
public void setEnabled(boolean enabled)
{
this.isEnabled = enabled;
}
/**
* Resets the controller based on the current state of the robot
*
* @param currentPose Current robot pose
* @param currentSpeeds Current robot relative chassis speeds
*/
@Override
public void reset(Pose2d currentPose, ChassisSpeeds currentSpeeds)
{
xController.reset();
yController.reset();
rotationController.reset();
}
/**
* Calculates the next output of the path following controller
*
* @param currentPose The current robot pose
* @param targetState The desired trajectory state
* @return The next robot relative output of the path following controller
*/
@Override
public ChassisSpeeds calculateRobotRelativeSpeeds(Pose2d currentPose, PathPlannerTrajectoryState targetState)
{
double xFF = targetState.fieldSpeeds.vxMetersPerSecond;
double yFF = targetState.fieldSpeeds.vyMetersPerSecond;
this.translationError = currentPose.getTranslation().minus(targetState.pose.getTranslation());
if (!this.isEnabled)
{
return ChassisSpeeds.fromFieldRelativeSpeeds(xFF, yFF, 0, currentPose.getRotation());
}
double xFeedback = this.xController.calculate(currentPose.getX(), targetState.pose.getX());
double yFeedback = this.yController.calculate(currentPose.getY(), targetState.pose.getY());
Rotation2d targetRotation = targetState.pose.getRotation();
if (rotationTargetOverride != null)
{
targetRotation = rotationTargetOverride.get().orElse(targetRotation);
}
double rotationFeedback = rotationController.calculate(currentPose.getRotation().getRadians(), targetRotation.getRadians());
double rotationFF = targetState.fieldSpeeds.omegaRadiansPerSecond;
if (xFeedbackOverride != null)
{
xFeedback = xFeedbackOverride.getAsDouble();
}
if (yFeedbackOverride != null)
{
yFeedback = yFeedbackOverride.getAsDouble();
}
if (rotFeedbackOverride != null)
{
rotationFeedback = rotFeedbackOverride.getAsDouble();
}
Translation2d translationVals = new Translation2d((xFF + xFeedback) / Constants.Swerve.maxSpeed, (yFF + yFeedback) / Constants.Swerve.maxSpeed);
if (SmartDashboard.getBoolean("Path Fencing", true))
{
SmartDashboard.putBoolean("Path fenced?", true);
for (int i = fieldGeoFence.length - 1; i >= 0; i--)
{
Translation2d inputDamping = fieldGeoFence[i].dampMotion(currentPose.getTranslation(), translationVals, robotRadius);
translationVals = inputDamping;
}
} else {SmartDashboard.putBoolean("Path fenced?", false);}
SmartDashboard.putNumber("X path speed", translationVals.getX() * Constants.Swerve.maxSpeed);
SmartDashboard.putNumber("Y path speed", translationVals.getY() * Constants.Swerve.maxSpeed);
return ChassisSpeeds.fromFieldRelativeSpeeds(translationVals.getX() * Constants.Swerve.maxSpeed, translationVals.getY() * Constants.Swerve.maxSpeed, rotationFF + rotationFeedback, currentPose.getRotation());
}
/**
* Is this controller for holonomic drivetrains? Used to handle some differences in functionality
* in the path following command.
*
* @return True if this controller is for a holonomic drive train
*/
@Override
public boolean isHolonomic()
{
return true;
}
/* PID OVERRIDES */
/* _____________ */
/**
* Begin overriding the X axis feedback.
*
* @param xFeedbackOverride Double supplier that returns the desired FIELD-RELATIVE X feedback in
* meters/sec
*/
public static void overrideXFeedback(DoubleSupplier xFeedbackOverride)
{
PPHolonomicDriveControllerGeoFenced.xFeedbackOverride = xFeedbackOverride;
}
/**
* Stop overriding the X axis feedback, and return to calculating it based on path following
* error.
*/
public static void clearXFeedbackOverride()
{
PPHolonomicDriveControllerGeoFenced.xFeedbackOverride = null;
}
/**
* Begin overriding the Y axis feedback.
*
* @param yFeedbackOverride Double supplier that returns the desired FIELD-RELATIVE Y feedback in
* meters/sec
*/
public static void overrideYFeedback(DoubleSupplier yFeedbackOverride)
{
PPHolonomicDriveControllerGeoFenced.yFeedbackOverride = yFeedbackOverride;
}
/**
* Stop overriding the Y axis feedback, and return to calculating it based on path following
* error.
*/
public static void clearYFeedbackOverride()
{
PPHolonomicDriveControllerGeoFenced.yFeedbackOverride = null;
}
/**
* Begin overriding the X and Y axis feedback.
*
* @param xFeedbackOverride Double supplier that returns the desired FIELD-RELATIVE X feedback in
* meters/sec
* @param yFeedbackOverride Double supplier that returns the desired FIELD-RELATIVE Y feedback in
* meters/sec
*/
public static void overrideXYFeedback(DoubleSupplier xFeedbackOverride, DoubleSupplier yFeedbackOverride)
{
overrideXFeedback(xFeedbackOverride);
overrideYFeedback(yFeedbackOverride);
}
/**
* Stop overriding the X and Y axis feedback, and return to calculating them based on path
* following error.
*/
public static void clearXYFeedbackOverride()
{
clearXFeedbackOverride();
clearYFeedbackOverride();
}
/**
* Begin overriding the rotation feedback.
*
* @param rotationFeedbackOverride Double supplier that returns the desired rotation feedback in
* radians/sec
*/
public static void overrideRotationFeedback(DoubleSupplier rotationFeedbackOverride)
{
PPHolonomicDriveControllerGeoFenced.rotFeedbackOverride = rotationFeedbackOverride;
}
/**
* Stop overriding the rotation feedback, and return to calculating it based on path following
* error.
*/
public static void clearRotationFeedbackOverride()
{
PPHolonomicDriveControllerGeoFenced.rotFeedbackOverride = null;
}
/** Clear all feedback overrides and return to purely using path following error for feedback */
public static void clearFeedbackOverrides()
{
clearXYFeedbackOverride();
clearRotationFeedbackOverride();
}
}