Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
36 changes: 29 additions & 7 deletions quail/src/main/java/com/mineinjava/quail/pathing/PathFollower.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,7 @@
import com.mineinjava.quail.util.geometry.Vec2d;
import java.util.ArrayList;

/**
* Class that helps you follow paths
*
* <p>TODO: Don't treat point as reached if angle is outside angular precision
*/
/** Class that helps you follow paths */
public class PathFollower {
private Path path;
private double speed;
Expand All @@ -41,6 +37,7 @@ public class PathFollower {
private double maxAcceleration;
private MiniPID turnController;
private double precision;
private double headingPrecision;
private Localizer localizer;
private double slowDownDistance;

Expand All @@ -64,6 +61,7 @@ public PathFollower(
double maxAcceleration,
MiniPID turnController,
double precision,
double headingPrecision,
double slowDownDistance,
double kP,
double minVelocity) {
Expand All @@ -75,6 +73,7 @@ public PathFollower(
this.maxAcceleration = maxAcceleration;
this.turnController = turnController;
this.precision = precision;
this.headingPrecision = headingPrecision;
this.slowDownDistance =
slowDownDistance; // TODO: in the future add an option to calculate it based on max accel.
this.kP = kP;
Expand All @@ -89,6 +88,7 @@ public PathFollower(
double maxAcceleration,
MiniPID turnController,
double precision,
double headingPrecision,
double slowDownDistance,
double kP,
double minVelocity) {
Expand All @@ -101,6 +101,7 @@ public PathFollower(
maxAcceleration,
turnController,
precision,
headingPrecision,
slowDownDistance,
kP,
minVelocity);
Expand All @@ -113,6 +114,7 @@ public PathFollower(
ConstraintsPair rotationPair,
MiniPID turnController,
double precision,
double headingPrecision,
double slowDownDistance,
double kP,
double minVelocity) {
Expand All @@ -125,6 +127,7 @@ public PathFollower(
translationPair.getMaxAcceleration(),
turnController,
precision,
headingPrecision,
slowDownDistance,
kP,
minVelocity);
Expand All @@ -143,11 +146,12 @@ public RobotMovement calculateNextDriveMovement() {
"localizer is null, ensure that you have instantiated the localizer object");
}

this.currentPose = this.localizer.getPose(); // get the current pose of the robot
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason this was moved?


if (this.isFinished()) {
return new RobotMovement(0, new Vec2d(0, 0)); // the path is over
}

this.currentPose = this.localizer.getPose();
this.loopTime = (System.currentTimeMillis() - this.lastTime) / 1000.0;
this.lastTime = System.currentTimeMillis();

Expand Down Expand Up @@ -229,7 +233,25 @@ public RobotMovement calculateNextDriveMovement() {

/** returns true if the robot is finished following the path. */
public Boolean isFinished() {
return this.path.isFinished();
this.currentPose = this.localizer.getPose(); // ensure latest pose is updated

// Check if the path is finished
if (this.path.isFinished()) {
// Check if the heading difference is within the allowed precision for the last point
double headingDifference =
Math.abs(
this.path.points.get(this.path.points.size() - 1).heading - this.currentPose.heading);
return headingDifference <= this.headingPrecision;
}

// Check if the heading difference is within the allowed precision for the current point
double headingDifference =
Math.abs(this.path.points.get(this.path.lastPointIndex).heading - this.currentPose.heading);
if (headingDifference >= this.headingPrecision) {
return false;
}

return false;
}

/**
Expand Down
62 changes: 62 additions & 0 deletions quail/src/test/java/quail/pathing/PathFollowerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@
package quail.pathing;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import com.mineinjava.quail.RobotMovement;
import com.mineinjava.quail.localization.KalmanFilterLocalizer;
import com.mineinjava.quail.localization.SwerveOdometry;
import com.mineinjava.quail.pathing.ConstraintsPair;
import com.mineinjava.quail.pathing.Path;
import com.mineinjava.quail.pathing.PathFollower;
Expand Down Expand Up @@ -72,6 +74,7 @@ void setUp() {

MiniPID turnController = new MiniPID(1, 0, 0);
double precision = 0.2;
double headingPrecision = 0.1;
double slowDownDistance = 0.25d;
double kP = 1;
double minVelocity = 0;
Expand All @@ -84,6 +87,7 @@ void setUp() {
rotationPair,
turnController,
precision,
headingPrecision,
slowDownDistance,
kP,
minVelocity);
Expand Down Expand Up @@ -156,4 +160,62 @@ void driveMovementsConvergeToPathAndFinishPath() {
}
assertTrue(this.pathFollower.isFinished());
}

@Test
void isFinishedWorksWithDifferentFinalHeading() {
// Modify the final point to have a different heading
Pose2d finalPoseWithDifferentHeading = new Pose2d(0, 2, Math.PI / 2); // 90 degrees
Path newPath =
new Path(
new ArrayList<Pose2d>() {
{
add(poseStart);
add(poseSecond);
add(poseThird);
add(poseFourth);
add(finalPoseWithDifferentHeading);
}
});

// Create a new PathFollower with a SwerveOdometry localizer (won't work with Kalman)
SwerveOdometry swerveOdometry =
new SwerveOdometry(
new ArrayList<Vec2d>() {
{
add(new Vec2d(1, 0));
add(new Vec2d(-1, 0));
}
});

// Set the new localizer and path
pathFollower.setLocalizer(swerveOdometry);
pathFollower.setPath(newPath);

// Simulate the robot moving along the path
for (int i = 0; i < path.points.size(); i++) {
pathFollower.getLocalizer().setPose(path.points.get(i)); // Set the pose to the next pose
pathFollower.calculateNextDriveMovement(); // Update

// Check if the path is finished
if (i < path.points.size() - 1) {
assertFalse(pathFollower.isFinished(), "Path should not be finished yet");
} else {
// Check if the path is finished on final point with incorrect heading, then correct heading
Pose2d finalPoseWithWrongHeading = new Pose2d(0, 2, Math.PI); // Outside heading precision
pathFollower.getLocalizer().setPose(finalPoseWithWrongHeading);
assertFalse(
pathFollower.isFinished(), "Path should not be finished due to incorrect heading");

Pose2d finalPoseWithCorrectHeading =
new Pose2d(0, 2, Math.PI / 2 - 0.05); // Within heading precision
pathFollower.getLocalizer().setPose(finalPoseWithCorrectHeading);
assertTrue(pathFollower.isFinished(), "Path should be finished, within heading precision");

pathFollower
.getLocalizer()
.setPose(finalPoseWithDifferentHeading); // Within heading precision
assertTrue(pathFollower.isFinished(), "Path should be finished, correct heading");
}
}
}
}
Loading