Pathfinding Tips Guide

I’ve noticed a lot of people asking questions about Pathfinding and the Ramsete controller tutorial. This thread is to aggregate your tips for navigating the new Ramsete tutorial or Pathfinding autons in general.

I’ll start with a tip my team learned by making a post about a problem we were having with pathfinding:

When using the Ramsete command, make sure to include a call to m_differentialDrive.feed(), otherwise the MotorSafety class will get unhappy and make your robot drive appear jittery. This is because it is periodically shutting off your motors because it thinks they have timed out.

4 Likes

Here are a few tips I have:

  • Read the docs. Trajectory Generation and Following with WPILib, Kinematics and Odometry, Robot Characterization, then finally the Trajectory Tutorial. I see there is a troubleshooting guide coming but it hasn’t been merged yet, so watch for that.
  • Make sure your gyro angle is in the correct direction. Left/counter-clockwise should yield a larger heading value.
  • The heading range should be [-180, 180]º, so if you’re using WPILib’s gyro.getAngle() you need to bring it in range with code like Math.IEEEremainder(yaw, 360.0d)
  • DO NOT use the (Talon 2020-) setting in the Characterization Tool. The max output is 1023 for Talon SRX’s. CTR did not normalize these values to [-1,1] yet.
  • Be sure to pick Velocity Loop Type in the characterization tool, not Position.
  • There are two places to enter your wheel diameter in characterization tool, be sure you enter it in both places. It goes in the Python config and in the box on the analysis page.
  • When you’re ready to run a trajectory (especially if you generated it with PathWeaver), you need to be sure your robot’s current pose matches the trajectory starting pose. Using transformBy is a suggested way to handle it.
  • Make sure units are consistent! I highly recommend using SI (meters). If you use meters, the RamseteController default b and zeta values are probably fine. Also, DifferentialDriveOdometry has a method called getPoseMeters() ao if you don’t use meters this will return a different unit, which I find confusing.
  • Head to this thread if you’re thinking about running closed-loop with Talon SRX’s instead of using PIDController on the roboRIO.
  • Be sure to zero your encoders before constructing DifferentDriveOdometry.
5 Likes

I did this. However, I also noticed that changing the value of the wheel diameter (or changing the units) does not change any of the values resulting from “Analyze Data” or “Calculate Optimal Controller Gains.” Which is puzzling to me.

1 Like

It does seem to affect kP and kD gains when I change it.

I would add that if you are using the DifferentialDrive() class to drive your robot outside of autonomous, for instance with something like m_drive.arcadedrive(). You may have issues with one side of your drivetrain being inverted for RamseteCommand as DifferentialDrive will invert the right side for you automatically.

I found the way to remedy this was to:

  1. Instantiate motors
  2. invert motor(s) on the right side (taking into account multiple motors and how followers may or may not need to be inverted relative to the lead motor)
  3. instantiate DifferentialDrive()
  4. call m_differentialdrive.setRightSideInverted(false);

This made both DifferentialDrive happy and returned the expected signedness for the encoder values to the RamseteCommand.

Hmm, the difference between the default .333 feet and 0.1524 meters is only about .05 meters. I’ll have to do the experiment again and watch more closely.

In addition to right-side-inverted and differentialDrive.feed(), I also have a tip if you are using DifferentialDrive in other places to drive your robot. I would recommend avoiding SpeedControllerGroup because is causes the motors to come out of follower mode.

For example, given:

WPI_TalonSRX rightMaster = new WPI_TalonSRX(0);
WPI_TalonSRX rightSlave = new WPI_TalonSRX(1);
WPI_TalonSRX leftMaster = new WPI_TalonSRX(2);
WPI_TalonSRX leftSlave = new WPI_TalonSRX(3);

Do this:

rightSlave.follow(rightMaster);
leftSlave.follow(leftMaster);
differentialDrive = new DifferentialDrive(leftMaster, rightMaster);

Don’t do this (even if you’re calling follow() elsewhere):

SpeedControllerGroup rightGroup = new SpeedControllerGroup(rightMaster, rightSlave);
SpeedControllerGroup leftGroup = new SpeedControllerGroup(leftMaster, leftSlave);
differentialDrive = new DifferentialDrive(leftGroup, rightGroup);
2 Likes

Are you saying that only .follow() should be used or that either a speed controller or a .follow() should be used, but not both?

Don’t use a SpeedControllerGroup, only use .follow(). SpeedControllerGroup takes the controllers out of follower mode (at least with Talon SRX’s).

The full story is that the analyzer wheel diameter box only affects the LQR-derived gains if you’re using a Talon with non-rotational units selected in the analyzer. We have to do this only for Talons in this certain situation because the Talons use native units internally. We’re hoping to transfer unit information from the logger in the future so that there isn’t as much confusion.

The bit of code that does this (for drive characterization) is here.

2 Likes

Another thing you might add to your list is my “Deep Dive into WPILib Trajectories” presentation.

I’ve used this to make freshman get a drivetrain tracking to 1” and 5 degrees of error in about 15 minutes of tuning with no help.

A good theoretical understanding makes it much easier to make your drivetrain track well… A lot of the issues people have with getting good trajectory tracking would go away if they at least knew a little bit about what’s going on behind the curtain, not to mention that learning is a deeply important part of a good FRC experience.

3 Likes

Another update: my trajectory troubleshooting guide was merged, and I changed the drive and simple motor characterization tools to find velocity gains by default.

1 Like

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.