How to properly convert neo Relative Encoders ticks to feet

Hello,

I am currently attempting to create a basic drive x distance auto, I am using the built in neo Relative encoders to do this but so far my calculations of ticks to feet appears to be way off.

How I am currently calculating, with the ticks parameter passed being encoder.getPosition();

    public double ticks2Feet(double ticks) {
        return ((ticks/42) * (6 * Math.PI)) / 12;
    }

My auto command:

package frc.robot.commands;

import edu.wpi.first.wpilibj2.command.CommandBase;
import frc.robot.subsystems.DriveTrain;

public class MoveFeet extends CommandBase {
    private final DriveTrain driveTrain;
    private final double feet;

    public MoveFeet(DriveTrain driveTrain, double feet) {
        this.driveTrain = driveTrain;
        this.feet = feet;
        addRequirements(driveTrain);
    }

    @Override
    public void initialize() {
        
    }

    @Override
    public void execute() {
        driveTrain.arcadeDrive(-0.2,0);
    }

    @Override
    public void end(boolean interuppted) {
        driveTrain.arcadeDrive(0, 0);
    }

    @Override
    public boolean isFinished() {
        return driveTrain.ticks2Feet(driveTrain.getLefEncoderPosition()) == feet 
        && 
        driveTrain.ticks2Feet(driveTrain.getRightEncoderPosition()) == feet;
    }
    
}

Does anyone have any ideas on why this could be wrong?

Is the /12 the gearbox ratio?

No, that is to convert it from inches to feet.

You don’t need to divide by 42, getPosition on a Neo returns rotations, so you shouldn’t have to deal with ticks

Ohhh I see, how should the algorithm work then?
Something like?:

    public double ticks2Feet(double ticks) {
        return (ticks * (6 * Math.PI)) / 12;
    }

Then noob question: Would I need to include gearbox ration into this as well?

Yes you would, and then that should cover it

leftEncoder.getPosition() * (Math.PI * Constants.DriveConstants.leftWheelRadius) / Constants.GearboxConstants.kDriveRatio

Is an example

Side note, you’re going to have a very hard time getting this to finish because you are using equals. Very rarely will the actual distance be exactly equal to the goal distance, especially since you are trying to do both sides at the same time. You should consider a threshold for the two sides and check if the measured distance is within that threshold. I would also average the two encoder values (add and divide by two) because you could run into a situation where one side goes beyond the threshold and the other side is still below it. In this case, your command will continue to run indefinitely because the two sides will never be in the threshold at the same time.

3 Likes

To add to this you’ll likely want to use a PID controller for position or better a ramsete controller and a spline path

Yea PID controller will be coming next just creating something basic for now.

Alright, if you have a chance I’d recommend throwing together some basic odometry to visualize everything inside AdvantageScope or something similar to make sure all your conversions are correct with a quick visual check

So something like?

    @Override
    public boolean isFinished() {
        double average = (driveTrain.getLefEncoderPosition() + driveTrain.getRightEncoderPosition()) / 2;
        return driveTrain.ticks2Feet(average) == feet;
    }

Use greater than, == rarely triggers and you’ll just keep driving forever

you’re close.

    @Override
    public boolean isFinished() {
        double average = (driveTrain.getLefEncoderPosition() + driveTrain.getRightEncoderPosition()) / 2;
        return Math.abs(driveTrain.ticks2Feet(average) - feet) <= threshold;
    }

where threshold is how accurate you want it to be. Maybe 0.25 ft

1 Like

OH that is what they meant got it thank you.

1 Like

Where threshhold is the wanted feet to travel or more like a margin of error from it?

When you want to cut off and stop because the bot will keep drifting forwards a bit

Threshold will be a margin of error, or how close is good enough. But if you are doing the method I described, you might want to add an if statement in your execute that checks if you are too far forward, that makes the robot then back up.

Not quite. v0ncent is using feet as the goal, so the threshold is how close the measurements need to be within the goal.

Not to further confuse you, but you could ignore most of all this and instead just replace both of your == with <= or >= in your original code and it would work how you originally intended. Which one you use is dependent on whether your feet variable and your measured distances are position or negative.

    @Override
    public boolean isFinished() {
        return driveTrain.ticks2Feet(driveTrain.getLefEncoderPosition()) >= feet 
        && 
        driveTrain.ticks2Feet(driveTrain.getRightEncoderPosition()) >= feet;
    }
2 Likes

true true