I agree with @catrix, I was recently working on very similar code and .schedule() gave me some issues. I ended up creating a sequential command group and it worked much better. Additionally, if you are running auto cycles from the source to the amp then you would always be returning from the same direction but if you want to be able to hold a button and align with the amp from anywhere on the field It seems like you could run into issues when trying to align with the amp from directions you don’t have a predefined alignment for. The code I worked on below has two parts, the first is just like yours, pathfinds to the amp from anywhere, but instead of using a predefined path for the fine tune alignment, I use PID controllers for the X, Y, Theta of the bot and pass those back into the drivetrain. This gets the error to nearly zero. Pathfinding to a predefined path will probably be slightly faster and smoother but PID controller may be more versatile. Below is the code structure:
public class PathfindCmd extends SequentialCommandGroup {
public PathfindCmd(Pose2d targetPose, DrivetrainSubsystem drivetrainSubsystem) {
addCommands(generatePath(drivetrainSubsystem, targetPose), new FineTunePoseCmd(drivetrainSubsystem, targetPose));
}
//generates a pathplanner path that pathfinds to target pose while avoiding field elements. Only gets close, not exact which is why we have a fine tune cmd.
public Command generatePath(DrivetrainSubsystem drivetrainSubsystem, Pose2d targetPose) {
PathConstraints constraints = new PathConstraints(
2.0,
2.0,
1.5,
1.5);
Command pathfindingCommand = new PathfindHolonomic(
targetPose,
constraints,
0.0, // Goal end velocity in m/s. Optional
PoseEstimatorSubsystem::getPose,
drivetrainSubsystem::getRobotRelativeSpeeds,
drivetrainSubsystem::driveRobotRelative,
new HolonomicPathFollowerConfig( // HolonomicPathFollowerConfig, this should likely live in your Constants class
new PIDConstants(.5, 0.1, 0.0),
new PIDConstants(.5, 0.1, 0.0),
//new PIDConstants(1.1, 0.0, 0.0),
//new PIDConstants(6.0, 0.0, 0.0),
4.5, // Placeholder
// AutoConstants.kMaxSpeedMetersPerSecond, // Max module speed, in m/s
Math.hypot(DriveConstants.TRACK_WIDTH / 2, DriveConstants.WHEEL_BASE / 2), // Drive base radius in meters. Distance from robot center to furthest module.
new ReplanningConfig()), // Rotation delay distance in meters. This is how far the robot should travel before attempting to rotate. Optional
drivetrainSubsystem // Reference to drive subsystem to set requirements
);
return pathfindingCommand;
}
class FineTunePoseCmd extends Command {
private DrivetrainSubsystem drivetrainSubsystem;
private double targetX;
private double targetY;
private Rotation2d targetRotation;
private final PIDController xController = new PIDController(2, 0, 0);
private final PIDController yController = new PIDController(2, 0, 0);
private final PIDController thetaController = new PIDController(0.1, 0, 0);
public FineTunePoseCmd(DrivetrainSubsystem drivetrainSubsystem_para, Pose2d targetPose) {
this.drivetrainSubsystem = drivetrainSubsystem_para;
xController.setTolerance(0.05);
yController.setTolerance(0.05);
thetaController.setTolerance(0.5);
targetX = targetPose.getX();
targetY = targetPose.getY();
targetRotation = targetPose.getRotation();
addRequirements(drivetrainSubsystem);
}
@Override
public void initialize() {
}
@Override
public void execute() {
double xVel = this.xController.calculate(PoseEstimatorSubsystem.getPose().getTranslation().getX(), targetX);
double yVel = this.yController.calculate(PoseEstimatorSubsystem.getPose().getTranslation().getY(), targetY);
double angVel = this.thetaController.calculate(DrivetrainSubsystem.getHeading(), targetRotation.getDegrees());
var chassisSpeeds = ChassisSpeeds.fromFieldRelativeSpeeds(xVel, yVel, angVel, DrivetrainSubsystem.getRotation2d());
SwerveModuleState[] moduleStates = DriveConstants.DRIVE_KINEMATICS.toSwerveModuleStates(chassisSpeeds);
drivetrainSubsystem.setModuleStates(moduleStates);
}
@Override
public void end(boolean interrupted) {
drivetrainSubsystem.stopModules();
}
@Override
public boolean isFinished() {
return false;
}
}
}