Disabled Ramsete Working Better Than When Ramsete is enabled

Hello! This is my first post on chief delphi, I’m the president and former software member on Team 93 New Apple Corps Robotics. We are testing out auton during the preseason and have been at it since September. We are working with our drivetrain from last year that has 6 falcons geared ~10:1 with a navx 2. We couldn’t get auton working last year for the at home competitions so figured we’d try for this year. We have been testing tons of paths. We first found that the predetermined b and zeta values (2.0, 0.7) would just make the robot spazz out of control so we tried disabling the ramsete controller that we passed into our ramsete command and the path has run flawlessly every time we’ve done that. Even measuring with a tape measure its accurate within centimeters. From there we’ve tried a different combination of tuning the b and zeta values but haven’t gotten any results remotely close to what happens with the disabled ramsete controller. Any thoughts on why this may be? Thank you!

The default gains should work fine for basically any robot because Ramsete turns pose errors into corrective velocity commands. The underlying acceleration-to-velocity dynamics are handled by separate velocity controllers outputting voltages, so Ramsete can assume the velocity commands will be perfectly tracked.

The behavior you describe is usually caused by units problems. The Ramsete control law requires SI units (meters, radians, etc.). This is due to the fact the authors of the original paper took the “mystery meat” approach when designing the control law (this is common for Lyapunov approaches in nonlinear control), and the dimensional analysis doesn’t work out.

To figure out what’s going on, you basically need to shove all the relevant data into NetworkTables so you can plot them on Glass. The desired pose, actual pose, velocity and angular velocity commands from Ramsete, and actual velocities are all good to look at here.

If things worked with Ramsete disabled, it sounds like you have a really good feedforward already. That’s a really good thing, because Ramsete should only be handling small disturbances anyway.

3 Likes

Alright, Thank you so much! I’ll check the units next time I have access to the bot!

Could you elaborate on what you mean by “disabling ramsete?” We have had occasional trouble achieving stable trajectories, so it would be very useful to learn a new diagnostic technique.

This is what we used to diagnose the problem. I believe this forces the robot to just use the feedforwards given from the trajectory but I could be mistaken. It’s a great tool for diagnosing issues with the code!

2 Likes

We checked our units and everything is in meters and both sides of the tank drive’s velocities are positive and the gyro is the correct way. Our PID is also darn accurate but the one thing we noticed that was interesting was that we are using falcons on the drivetrain but using wpi pid loops, as a result when we pass in the get wheel speeds method to the ramsette controller we are passing in the falcons velocity method *10 (because it reports the raw ticks every 100ms) and then converting that to meters. Is this a problem? It’s the only thing we’ve found that may be the issue

Our Ramsete Code is the following

RamseteCommand ramseteCommand = new RamseteCommand(exampleTrajectory, subsystem::getPose, new RamseteController(),

                new SimpleMotorFeedforward(TankdriveConstantsFalcon.ksVolts,

                        TankdriveConstantsFalcon.kvVoltSecondsPerMeter,

                        TankdriveConstantsFalcon.kaVoltSecondsSquaredPerMeter),

                TankdriveConstantsFalcon.kDriveKinematics, subsystem::getWheelSpeeds,

                leftController,

                rightController,

                // RamseteCommand passes volts to the callback

                (leftVolts, rightVolts) -> {

        subsystem.tankDriveVolts(leftVolts, rightVolts);

        leftMeasurement.setNumber(subsystem.getWheelSpeeds().leftMetersPerSecond);

        leftReference.setNumber(leftController.getSetpoint());

        rightMeasurement.setNumber(subsystem.getWheelSpeeds().rightMetersPerSecond);

        rightReference.setNumber(rightController.getSetpoint());

    }, subsystem);

        // Reset odometry to the starting pose of the trajectory.

        subsystem.resetOdometry(exampleTrajectory.getInitialPose());

        // Run path following command, then stop at the end.

        return ramseteCommand.andThen(() -> subsystem.tankDriveVolts(0, 0));

    }

And our “important” methods we are referencing are the following

public void tankDriveVolts(double leftVolts, double rightVolts) {

    // System.out.println( "l: " + leftVolts);

    // System.out.println( "r: " + -rightVolts);

    LeftSpeedControllerGroup.setVoltage(leftVolts);

    RightSpeedControllerGroup.setVoltage(-rightVolts);

    // System.out.println(leftVolts);

    Drive.feed(); // is what makes it update(makes it so error output not updated often enough

                  // doesnt happen)

  }

  public DifferentialDriveWheelSpeeds getWheelSpeeds() {

    // System.out.println("left" + convertTicksToMeters((getLeftVelocity() * 10)));

    // System.out.println("right" + convertTicksToMeters((getRightVelocity() * 10)));

    return new DifferentialDriveWheelSpeeds(convertTicksToMeters((getLeftVelocity() * 10)),

        convertTicksToMeters((getRightVelocity() * 10)));

  }

  public double convertTicksToMeters(double Ticks) {

    return (((Ticks / TankdriveConstantsFalcon.falconEncoderConstant / TankdriveConstantsFalcon.falconGearRatio)

        * TankdriveConstantsFalcon.wheelCircumference6inch) / 39.37);

  }

And here’s our constants:

public static final double ksVolts = 0.557;

    public static final double kvVoltSecondsPerMeter = 2.29;

    public static final double kaVoltSecondsSquaredPerMeter = 0.0961;

    public static final double trackWidth = 1.000267645377219;

    public static final DifferentialDriveKinematics kDriveKinematics = new DifferentialDriveKinematics(trackWidth); // .875

    public static final double kMaxSpeedMetersPerSecond = 1.5;

    public static final double kMaxAccelerationMetersPerSecondSquared = 1.5;

    public static final double kRamseteB = 2;

    public static final double kRamseteZeta = 0.7;

    public static final int maxVoltage = 10;

    public static final double kPDriveVel = 0.29;

Is there anything we are just missing or that’s flatout wrong? We’ve been working on this for like weeks now and just hoping we can find the issue. Thanks!

This sounds like a very likely candidate.

Hello! We re-characterized the robot and got values within margin of error(.01) of what we originally had other than the p-gain that is now at 1.64 and it is still incapable of driving better than the disabled ramsete controller. We’ve gone back to manually tuning the values but have seen no progress still. Is there variable that would encourage very jerky inaccurate movement even when pid values seem correct? is there an underlying problem that you could think of? again, any help is appreciated

No.

My advice remains the same as my prior post. Did you try using SI units everywhere?

yes, i believe I found the issue, in the frc characterization tool we run our analysis with our units set to meters with the units per rotation being .479, but then our max velocity error is 1.5 which is way way way too high so our p gain is way off. I think… I checked all the math with the feedforwards and then solved for a p gain with a hypothetical error scenario and our p gain is off by at minimum a factor of 5

1 Like