Skip to content

Commit

Permalink
C++ Pathfinding (#379)
Browse files Browse the repository at this point in the history
  • Loading branch information
mjansen4857 authored Oct 8, 2023
1 parent 587e6e7 commit fd4dcf7
Show file tree
Hide file tree
Showing 13 changed files with 1,609 additions and 23 deletions.
3 changes: 2 additions & 1 deletion pathplannerlib/.vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
"xstddef": "cpp",
"xstring": "cpp",
"xtr1common": "cpp",
"xutility": "cpp"
"xutility": "cpp",
"unordered_set": "cpp"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public PathfindingCommand(
* @param targetPose the pose to pathfind to, the rotation component is only relevant for
* holonomic drive trains
* @param constraints the path constraints to use while pathfinding
* @param goalEndVel The goal end velocity when reaching the target pose
* @param poseSupplier a supplier for the robot's current pose
* @param speedsSupplier a supplier for the robot's current robot relative speeds
* @param outputRobotRelative a consumer for the output speeds (robot relative)
Expand Down Expand Up @@ -123,7 +124,6 @@ public void initialize() {
currentTrajectory = null;

Pose2d currentPose = poseSupplier.get();
PathPlannerLogging.logCurrentPose(currentPose);

controller.reset(currentPose, speedsSupplier.get());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ public class ADStar {
public static int NODE_Y = (int) Math.ceil(FIELD_WIDTH / NODE_SIZE);

private static final double EPS = 2.5;
private static final int heuristicType = 1; // 0: manhattan, 1: euclidean

private static final HashMap<GridPosition, Double> g = new HashMap<>();
private static final HashMap<GridPosition, Double> rhs = new HashMap<>();
Expand Down Expand Up @@ -97,7 +96,7 @@ public static void ensureInitialized() {
FIELD_LENGTH = ((Number) fieldSize.get("x")).doubleValue();
FIELD_WIDTH = ((Number) fieldSize.get("y")).doubleValue();
} catch (Exception e) {
e.printStackTrace();
// Do nothing, use defaults
}
}

Expand Down Expand Up @@ -130,7 +129,7 @@ private static void runThread() {
}
}

if (!needsReset || !doMinor || !doMajor) {
if (!needsReset && !doMinor && !doMajor) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
Expand Down Expand Up @@ -240,7 +239,7 @@ private static GridPosition findClosestNonObstacle(GridPosition pos) {

public static void setDynamicObstacles(
List<Pair<Translation2d, Translation2d>> obs, Translation2d currentRobotPos) {
List<GridPosition> newObs = new ArrayList<>();
Set<GridPosition> newObs = new HashSet<>();

for (var obstacle : obs) {
var gridPos1 = getGridPos(obstacle.getFirst());
Expand Down Expand Up @@ -268,17 +267,17 @@ public static void setDynamicObstacles(
needsReset = true;
doMinor = true;
doMajor = true;
}

if (dynamicObstacles.contains(getGridPos(currentRobotPos))) {
// Set the start position to the closest non-obstacle
setStartPos(currentRobotPos);
if (dynamicObstacles.contains(getGridPos(currentRobotPos))) {
// Set the start position to the closest non-obstacle
setStartPos(currentRobotPos);
}
}
}

private static List<Translation2d> extractPath() {
if (sGoal.equals(sStart)) {
return List.of(gridPosToTranslation2d(sStart));
return List.of(realGoalPos);
}

List<GridPosition> path = new ArrayList<>();
Expand All @@ -293,9 +292,9 @@ private static List<Translation2d> extractPath() {
gList.put(x, g.get(x));
}

Map.Entry<GridPosition, Double> min = null;
Map.Entry<GridPosition, Double> min = Map.entry(sGoal, Double.POSITIVE_INFINITY);
for (var entry : gList.entrySet()) {
if (min == null || entry.getValue() < min.getValue()) {
if (entry.getValue() < min.getValue()) {
min = entry;
}
}
Expand Down Expand Up @@ -488,7 +487,7 @@ private static double cost(GridPosition sStart, GridPosition sGoal) {
return Double.POSITIVE_INFINITY;
}

return Math.hypot(sGoal.x - sStart.x, sGoal.y - sStart.y);
return heuristic(sStart, sGoal);
}

private static boolean isCollision(GridPosition sStart, GridPosition sEnd) {
Expand All @@ -508,9 +507,7 @@ private static boolean isCollision(GridPosition sStart, GridPosition sEnd) {
s2 = new GridPosition(Math.max(sStart.x, sEnd.x), Math.min(sStart.y, sEnd.y));
}

if (obstacles.contains(s1) || obstacles.contains(s2)) {
return true;
}
return obstacles.contains(s1) || obstacles.contains(s2);
}

return false;
Expand Down Expand Up @@ -572,11 +569,7 @@ private static Pair<GridPosition, Pair<Double, Double>> topKey() {
}

private static double heuristic(GridPosition sStart, GridPosition sGoal) {
if (heuristicType == 0) {
return Math.abs(sGoal.x - sStart.x) + Math.abs(sGoal.y - sStart.y);
} else {
return Math.hypot(sGoal.x - sStart.x, sGoal.y - sStart.y);
}
return Math.hypot(sGoal.x - sStart.x, sGoal.y - sStart.y);
}

private static int comparePair(Pair<Double, Double> a, Pair<Double, Double> b) {
Expand All @@ -596,7 +589,8 @@ public static GridPosition getGridPos(Translation2d pos) {
}

private static Translation2d gridPosToTranslation2d(GridPosition pos) {
return new Translation2d(pos.x * NODE_SIZE, pos.y * NODE_SIZE);
return new Translation2d(
(pos.x * NODE_SIZE) + (NODE_SIZE / 2.0), (pos.y * NODE_SIZE) + (NODE_SIZE / 2.0));
}

public static class GridPosition implements Comparable<GridPosition> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
#include "pathplanner/lib/commands/PathfindingCommand.h"
#include "pathplanner/lib/pathfinding/ADStar.h"
#include <vector>

using namespace pathplanner;

PathfindingCommand::PathfindingCommand(
std::shared_ptr<PathPlannerPath> targetPath,
PathConstraints constraints, std::function<frc::Pose2d()> poseSupplier,
std::function<frc::ChassisSpeeds()> speedsSupplier,
std::function<void(frc::ChassisSpeeds)> output,
std::unique_ptr<PathFollowingController> controller,
units::meter_t rotationDelayDistance, frc2::Requirements requirements) : m_targetPath(
targetPath), m_targetPose(), m_goalEndState(0_mps, frc::Rotation2d()), m_constraints(
constraints), m_poseSupplier(poseSupplier), m_speedsSupplier(
speedsSupplier), m_output(output), m_controller(std::move(controller)), m_rotationDelayDistance(
rotationDelayDistance) {
AddRequirements(requirements);

ADStar::ensureInitialized();

frc::Rotation2d targetRotation;
for (PathPoint p : m_targetPath->getAllPathPoints()) {
if (p.holonomicRotation.has_value()) {
targetRotation = p.holonomicRotation.value();
break;
}
}

m_targetPose = frc::Pose2d(m_targetPath->getPoint(0).position,
targetRotation);
m_goalEndState = GoalEndState(
m_targetPath->getGlobalConstraints().getMaxVelocity(),
targetRotation);
}

PathfindingCommand::PathfindingCommand(frc::Pose2d targetPose,
PathConstraints constraints, units::meters_per_second_t goalEndVel,
std::function<frc::Pose2d()> poseSupplier,
std::function<frc::ChassisSpeeds()> speedsSupplier,
std::function<void(frc::ChassisSpeeds)> output,
std::unique_ptr<PathFollowingController> controller,
units::meter_t rotationDelayDistance, frc2::Requirements requirements) : m_targetPath(), m_targetPose(
targetPose), m_goalEndState(goalEndVel, targetPose.Rotation()), m_constraints(
constraints), m_poseSupplier(poseSupplier), m_speedsSupplier(
speedsSupplier), m_output(output), m_controller(std::move(controller)), m_rotationDelayDistance(
rotationDelayDistance) {
AddRequirements(requirements);

ADStar::ensureInitialized();
}

void PathfindingCommand::Initialize() {
m_currentTrajectory = PathPlannerTrajectory();

frc::Pose2d currentPose = m_poseSupplier();

m_controller->reset(currentPose, m_speedsSupplier());

if (m_targetPath) {
m_targetPose = frc::Pose2d(m_targetPath->getPoint(0).position,
m_goalEndState.getRotation());
}

if (ADStar::getGridPos(currentPose.Translation())
== ADStar::getGridPos(m_targetPose.Translation())) {
Cancel();
} else {
ADStar::setStartPos(currentPose.Translation());
ADStar::setGoalPos(m_targetPose.Translation());
}

m_startingPose = currentPose;
}

void PathfindingCommand::Execute() {
frc::Pose2d currentPose = m_poseSupplier();
frc::ChassisSpeeds currentSpeeds = m_speedsSupplier();

PathPlannerLogging::logCurrentPose(currentPose);
PPLibTelemetry::setCurrentPose(currentPose);

if (ADStar::isNewPathAvailable()) {
std::vector < frc::Translation2d > bezierPoints =
ADStar::getCurrentPath();

if (bezierPoints.size() >= 4) {
auto path =
std::make_shared < PathPlannerPath
> (bezierPoints, std::vector<RotationTarget>(), std::vector<
ConstraintsZone>(), std::vector<EventMarker>(), m_constraints, m_goalEndState, false);

if (currentPose.Translation().Distance(path->getPoint(0).position)
<= 0.25_m) {
m_currentTrajectory = PathPlannerTrajectory(path,
currentSpeeds);

PathPlannerLogging::logActivePath(path);
PPLibTelemetry::setCurrentPath(path);
} else {
auto replanned = path->replan(currentPose, currentSpeeds);
m_currentTrajectory = PathPlannerTrajectory(replanned,
currentSpeeds);

PathPlannerLogging::logActivePath(replanned);
PPLibTelemetry::setCurrentPath(replanned);
}

m_timer.Reset();
m_timer.Start();
}
}

if (m_currentTrajectory.getStates().size() > 0) {
PathPlannerTrajectory::State targetState = m_currentTrajectory.sample(
m_timer.Get());

// Set the target rotation to the starting rotation if we have not yet traveled the rotation
// delay distance
if (currentPose.Translation().Distance(m_startingPose.Translation())
< m_rotationDelayDistance) {
targetState.targetHolonomicRotation = m_startingPose.Rotation();
}

frc::ChassisSpeeds targetSpeeds =
m_controller->calculateRobotRelativeSpeeds(currentPose,
targetState);

units::meters_per_second_t currentVel = units::math::hypot(
currentSpeeds.vx, currentSpeeds.vy);

PPLibTelemetry::setCurrentPose(currentPose);
PPLibTelemetry::setTargetPose(targetState.getTargetHolonomicPose());
PathPlannerLogging::logCurrentPose(currentPose);
PathPlannerLogging::logTargetPose(targetState.getTargetHolonomicPose());
PPLibTelemetry::setVelocities(currentVel, targetState.velocity,
currentSpeeds.omega, targetSpeeds.omega);
PPLibTelemetry::setPathInaccuracy(m_controller->getPositionalError());

m_output(targetSpeeds);
}
}

bool PathfindingCommand::IsFinished() {
if (m_targetPath) {
frc::Pose2d currentPose = m_poseSupplier();
frc::ChassisSpeeds currentSpeeds = m_speedsSupplier();

units::meters_per_second_t currentVel = units::math::hypot(
currentSpeeds.vx, currentSpeeds.vy);
units::meter_t stoppingDistance = units::math::pow < 2
> (currentVel) / (2 * m_constraints.getMaxAcceleration());

return currentPose.Translation().Distance(
m_targetPath->getPoint(0).position) <= stoppingDistance;
}

if (m_currentTrajectory.getStates().size() > 0) {
return m_timer.HasElapsed(m_currentTrajectory.getTotalTime());
}

return false;
}

void PathfindingCommand::End(bool interrupted) {
m_timer.Stop();

// Only output 0 speeds when ending a path that is supposed to stop, this allows interrupting
// the command to smoothly transition into some auto-alignment routine
if (!interrupted && m_goalEndState.getVelocity() < 0.1_mps) {
m_output(frc::ChassisSpeeds());
}
}
Loading

0 comments on commit fd4dcf7

Please sign in to comment.