PathPlanner - Issues

Hardware:

  • MK4i
  • NEO (turning and driving)
  • CTR CANcoder absolute encoder

Programming:

Behavior I expect:

Behavior I observe:

  • It runs a path that looks like this:

We ran the following custom paths using this method and they worked great. They got within a couple centimeters of their target consistently.

		PathPlannerTrajectory xtraj = PathPlanner.generatePath(
			new PathConstraints(3, 4), 
			new PathPoint(new Translation2d(0, 0), Rotation2d.fromDegrees(0)),
			new PathPoint(new Translation2d(4, 0), Rotation2d.fromDegrees(0)));

		PathPlannerTrajectory ytraj = PathPlanner.generatePath(
			new PathConstraints(3, 4), 
			new PathPoint(new Translation2d(0, 0), Rotation2d.fromDegrees(-90)),
			new PathPoint(new Translation2d(0, -4), Rotation2d.fromDegrees(-90)));


The following rotated 180, drove forward 2 meters, but also shifted left in the y about .5 meters:

		PathPlannerTrajectory trajRotationTuning = PathPlanner.generatePath(
			new PathConstraints(1, 2),
				new PathPoint(new Translation2d(0,0), Rotation2d.fromDegrees(0), Rotation2d.fromDegrees(0)),
				new PathPoint(new Translation2d(2, 0), Rotation2d.fromDegrees(0), Rotation2d.fromDegrees(180)));

I cannot tell if my methods are bad, what I’m doing in PathPlanner is bad, my SwerveModule is bad, or what else. Any ideas what I can check?

Did you try connecting PathPlannerLib Server to see what the robot thinks it’s doing? We found this to be really valuable debug tool!

1 Like

What are your pid constants for the path following command? It looks like it may be falling behind a bit.

  • kP for PathPlanner X and Y = .5
  • kP for PathPlanner Rot = .8

Like I said, we tuned these using straight paths in the X and Y and a 180 rotation + 2m movement in the x direction for rotation. Robot goes exactly where we tell it on straight paths

In your SwerveModule, your turning ProfiledPIDController doesn’t look right to me.

  • Your turning constraints seem awfully high. Can your robot rotate at 200 revolutions per second?
  • You might want to check your units. The turning controller’s calculate method should be returning a velocity in radians per second. However, you are adding it with the feedforward voltage, and calling motor.setVoltage().

The PID outputs volts

1 Like

Yeah, you’re right. It depends on your PID units.

We kept increasing constraints because the modules were so sluggish. That is 100% not what it should be, it cannot move that fast. I’m sure that is an issue.

But I don’t know how to make them not so slow… Feed forward values turned out great when I did it for the turning motors. Graphs were spot on so I’m not sure.

I totally missed that you put them in the original post, oops.

Because you tuned for a straight path, you might be getting a bunch of error in more complex paths. It is pretty easy for the robot to follow a straight path really well with 0 P constants since the FF will get you pretty close. It becomes a lot harder when there’s curves, momentum, module rotations, etc. to deal with.

A little example to show how little a P value of 0.5 for X and Y is actually doing:
Say you have an error of 0.1 meters and have a current target velocity of 2 m/s. Your output velocity will be targetVel + (P * error), so 2 + (0.5 * 0.1), or 2.05 m/s. If the output stayed constant it would take 2 seconds to correct for that error.

A P value I usually recommend as a starting point would be ~5. In that same example, the output would be 2.5 m/s. So it will be much more capable of correcting for error quickly.

There may be some other issues somewhere else, but I’d try giving it a go with a higher translation P and see if that helps.

1 Like

I gotchya, that makes sense. I’ll adjust my P value and see what happens.

The issue I have doing that is when we had a P value that high, the robot would drive insanely off course. I had it drive a 1x1 m box and it drove across the room. I moved it back down and it was fine.

Regardless, I’ll report back.

Do you need to have a different P value for different path constraints? (max velocity/acceleration)

I agree with @mjansen4857. Our X and Y P are currently at 8.

I still think you should review your turning controller. When I use your values to turn from 0 to 90-degrees, the feed forward calculates to 32.75 volts.

    double kModuleTurningControllerP = 4.75;
		double kModuleTurningControllerI = 0;
		double kModuleTurningControllerD = 0;

    double[] kAngularPID = {
      kModuleTurningControllerP,
      kModuleTurningControllerI,
      kModuleTurningControllerD };

    var controller = new ProfiledPIDController(
      kAngularPID[0],
      kAngularPID[1],
      kAngularPID[2],
      new TrapezoidProfile.Constraints(
        2 * Math.PI * 200,
        2 * Math.PI * 600));

    double kvTurning = .43205;
    double ksTurning = .17161; // Tuned February 2, 2023


    SimpleMotorFeedforward turnFeedForward = new SimpleMotorFeedforward(ksTurning, kvTurning);

    var output = controller.calculate(0, Units.degreesToRadians(90));
    var feedForward = turnFeedForward.calculate(controller.getSetpoint().velocity);

    System.out.println("Output = " + output);
    System.out.println("FF = " + feedForward);
    System.out.println("Voltage = " + (output + feedForward));

Output:

Output = 3.5814156250923643
FF = 32.74741254360328
Voltage = 36.328828168695644

Wow that helps a lot.

For the constraints, am I figuring out what the literal max velocity and acceleration of the physical module/motor is? Or is there another way I am supposed to figure it out?

It will be in the units you’re using.

If you got your feed forward values from SysID they are most likely in rotations, but it depends what you selected, radians is an option in SysID. If it’s rotations, you have to convert from your target in radians to rotations before calculating. When I try that, I get feedforward of 8.93 volts.

turnFeedForward.calculate(
        Units.radiansToRotations(controller.getSetpoint().velocity));

I expected the turning controller to be in radians, and the fact that your constraints had Pi in them seemed to confirm that. But if you’re working in voltage, your constraints will also be voltage. That means your velocity constraint would be voltage, and your acceleration would be voltage/second. The constraint values would be no more than 12 in this case.

Oh my goodness. Duh. Thanks that helps a lot.

They shouldn’t be different.

I’d probably recommend using a normal position PID for your module rotations instead of a profiled PID controller. The motion will be smoother if its profiled, but it will reduce your rotation response time which can play a part in causing the oscillations at higher X/Y P values. We are using a position PID on our Mk4s and the module can do a 90 degree turn nearly instantly.

Further note on constraints (this applies to both your module constraints and the path constraints), you will want to constrain the max velocity to be a bit below the actual maximum of the system. This will give it some headroom to actually correct for error.

I switched the turning PID from profiled to normal. The P value is gonna change. I am up to 8, I believe right now and was wondering what yours looks like. I had to pause working on Path Planner to working on this (which I suppose I used by PP).

I also printed out the feedforward and PID calculations and am seeing much more reasonable voltage outputs.

The PID for our module rotation? It won’t really be too useful to you since it is for a falcon running phoenix pro, not a spark max. But, we have P = 6 and D = 3. That is in terms of motor rotations to output volts

Understandable that it is entirely different. I more or less wanted to know if 8 is obscene, if it is supposed to be under one, or if it is normal to be in double digits. This helps.

I cannot get a regular PID to work. I posted this on discord:

If I use this:

        final var angularPIDOutput = m_turningPIDController.calculate(m_moduleAngleRadians, optimizedState.angle.getRadians());
        final var angularFFOutput = turnFeedForward.calculate(m_turningPIDController.getSetpoint());


        final var turnOutput = angularPIDOutput + angularFFOutput;

        turningMotor.setVoltage(turnOutput);

the module is off by about 8 degrees at 90 degreee setpoint. It is off by about 14 degrees at the 180 degree setpoint. If I remove the angularFFOutput it wil go to its position. Obviously this is not ideal. What am I doing wrong with the FF?

If I use a profiled PID, I have to use HUGE velocity and acceleration values, which apparently makes my Path Planner not work.

If I use a regular PID, the feedforward screws up the angle. At 180 the FF sends -1.5V and the PID sends 1.5V.