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.
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.
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.
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:
Instantiate motors
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)
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);
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.
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.