Path Planner Crashing from manually generated path

I am having trouble using PathPlanner for an offseason project of mine. I am trying to generate a trajectory from a drawn line on a field image. I created a list of points at the pathplanner arena scale and created a .path file based off of the points by iterating through the 2D list of points in a for loop and concatenating a waypoint to a string. Here is an example of a program-generated .path file:

Path File

It matches the PathPlanner app’s generated paths by format from what I can tell and is syntactically valid based on a JSON format validator website. I place the file in the correct folder in VSCode for my PathPlanner project (where the app generated files are and function correctly). However, by doing this, whenever I attempt to open PathPlanner, it crashes immediately. This is the 2023.4.1 MacOS App Store version. Like I said, before adding this file, the app worked fine. There are only 27 points in this waypoint, which doesn’t seem too big, although I may be wrong. Here is my crash log if it’s of any help:

Crash Log

Any help would be greatly appreciated.

I am not familiar with PathPlanner’s JSON format, but looking at your path, I notice that every point in the path is listed as an “anchorPoint” without links to previous or next waypoint. I suspect that only the first waypoint in the path should be designated as an anchor?

Does your JSON format for the later waypoints match what you find in a working path definition?

First time posting on here, so let me know if I did anything wrong

Comparing this to our generated paths, a difference is that we have prevControl and nextControl as points for each of our anchor points (except the first one doesn’t have a prev, and the last doesn’t have a next). I don’t know how PathPlanner uses these, but my guess would be that they are responsible for controlling the curve between points, and it can’t draw the path between them without it.

1 Like

The prev/next control points are all null, is that valid?

I would suggest comparing against a program-generated path more closely to see what’s different.

Do you mean like where prevControl is same as the X coordinate and nextControl is the Y? I assumed that if I put them to null they would either automatically generate or they are just straight lines which would be fine because I have simplified the points to the necessary ones for the drawn trajectory curve to maintain its definition.

That’s how all of the points are like comparing to the app generated paths.

Looking at our code, we have an x and a y for each control, I think if you try setting them to the next/last point in the sequence it may try and draw a path. I am not sure if there is some set of checks on where they need to be.

Here is the relevant parts of one of our points
“prevControl”: {
“x”: 5.754393969942998,
“y”: 5.131012192487412
“nextControl”: {
“x”: 3.0611114413718203,
“y”: 4.704575792130308

The control coordinates aren’t those of the next or last point in our generated paths, but you could try that

So if I have points like:

[[2, 3], [5, 6], [8, 10]]

The prevControl for anchor point [5, 6] should be:

“prevControl”: {
“x”: 2,
“y”: 3

And the nextControl should be:

“prevControl”: {
“x”: 8,
“y”: 10

Maybe, I am not really sure, that isn’t how pathplanner would generate them, but it may work. I don’t have a ton of experience with it. I would try it.

They describe the Bézier curve, so I think setting them to the next or previous points could work for you. Here’s another post from this site that has some details on the file

Paths are saved to .path files in the src/main/deploy/pathplanner directory of the project. These files are JSON formatted and are essentially only a list of every waypoint on the path. PathPlanner paths are Bézier curves so each waypoint has 3 coordinate pairs that describe it (2 for the start and end point). On top of these 3 points, each waypoint contains other info such as the rotation for holonomic drive trains, the velocity override, if the point is a reversal or not, and if the waypoint is locked in the GUI or not. Its probably better to just show an example of a waypoint so here’s an example of a path file with all but 1 waypoint removed:

"waypoints": [
        "anchorPoint": {"x": 5, "y": 5},
        "prevControl": {"x": 4, "y": 5},
        "nextControl": {"x": 6, "y": 5},
        "holonomicAngle": 0,
        "isReversal": false,
        "velOverride": null,
        "isLocked": false

I don’t think using the actual previous/next points as the control points will have very good results for your actual path. I’d recommend making them a very small distance (maybe 0.01) from the waypoint, in the direction of the previous/next points. This will minimize the effect of the control points on the path. You can do something more advanced from there if desired but that should be a good starting point.

So, if the next point is less than the current point you subtract 0.01 from the point for the nextControl and add 0.01 if opposite? I’ll try this, although, what would be the effect of using the previous/next points as control points?

That may be fine depending on the exact waypoints but might not be. The previous control point needs to be in the exact opposite direction (but not magnitude) from the waypoint, so for example if the previous control point is {+0.01,-0.01} from the waypoint, the next control point will need to be {-0.01,+0.01}, or some multiple of that, from the waypoint.

As for why this is good, I would encourage opening up the PathPlanner GUI, draw up a path, and play around with the control points, including hitting the play button and watching what happens. That will help you develop some intuition for how the control points affect the path.

The super short answer is that very low-distance control points will have relatively little effect on the path, which is probably a good starting point for your application here. Putting the control points at the prev/next points is probably going to cause some yo-yoing (which you can observe by testing in the PP GUI).

1 Like
      "anchorPoint": {{
        "x": {field_points[i][0]},
        "y": {field_points[i][1]}
      "prevControl": {{
        "x": {field_points[i][0] - (control_increment * -1 if field_points[i-1][0] < field_points[i][0] else 1)},
        "y": {field_points[i][1] - (control_increment * -1 if field_points[i-1][1] < field_points[i][1] else 1)}
      "nextControl": {{
        "x": {field_points[i][0] + (control_increment * -1 if field_points[i+1][0] < field_points[i][0] else 1)},
        "y": {field_points[i][1] + (control_increment * -1 if field_points[i+1][1] < field_points[i][1] else 1)}

Above is my current algorithm for generating the control points, implementing the method you described. Using this method, I run into a few issues: Primarily, it causes lots of loops, and I want to discover why. I believe that the prevControl and nextControl need to form a 180 degree angle with the anchorPoint, which is supported by the fact that in the PathPlanner app when you manipulate one of the control points it maintains the 180 degree angle and when I start to change the path that I generated inside the app UI it snaps back to a 180 degree angle. Also, for the control points that are not previous control points on the anchorPoint, the control points are a length of 1 from the anchorPoint, not a length of the control_increment variable (which is currently 0.05). Changing the control_increment does not resolve the issue. Aside from the start and end point, the points’ control points have only three patterns:

  1. the previous control is directly 1 above the anchor and the next control is directly 1 to the right
  2. The previous control is directly 1 above the anchor and the next control is 1 length pointing 45 degrees (up and right)
  3. The previous control is directly 1 on top of the anchor and the next control is 1 length pointing 45 degrees (up and right)
    I believe, for one of the reasons I pointed out earlier, that the control points are defaulting, which is causing bad curves that intersect, forming lots of loops. Here is a screenshot of the generated trajectory in PathPlanner: