Encoders

Encoders are devices that measure the amount a motor rotates. Luckily for us, the Spark motors have built-in encoders!

Creating Encoder Objects

Parameters:

  • 2 integers (int) -> Encoder objects have 2 IDs, unlike Spark objects, these 2 integer parameters refer to the 2 IDs, respectively.

The Encoder IDs function exactly like SparkIDs- they are here to differentiate Encoder objects from each other. Luckily for you, like the Spark objects, the Encoders have already been referenced in the RomiDrivetrain class! Here is the code of the Encoder objects being declared.

// The Romi has onboard encoders that are hardcoded
// to use DIO pins 4/5 and 6/7 for the left and right
private final Encoder m_leftEncoder = new Encoder(4, 5);
private final Encoder m_rightEncoder = new Encoder(6, 7);

Encoder Configuration

You might find something like this in the RomiDrivetrain.

Encoders, every so often, update their positions, so the user can do important calculations involving them. Every time the encoder does this, it is called a pulse. Different encoder brands set their encoders to get pulses

An example of something we can do with pulses is finding out the distance an encoder travels.

If we want to make encoders return the distance they travel in other units, such as inches and meters, we'll have to calculate how much a point on the edge of the wheel would move when the Spark's wheel does a full rotation. Then, divide it by the number of revolutions per pulse.

To do this, we can just use the formula of the circumference, C=πdC = πd, using the diameter of the wheel as d. Then, we divide it by the number of pulses every revolution. As you see, this is already done for you.

private static final double kCountsPerRevolution = 1440.0;
private static final double kWheelDiameterInch = 2.75591; // 70 mm

// 
m_leftEncoder.setDistancePerPulse((Math.PI * kWheelDiameterInch) / kCountsPerRevolution);
m_rightEncoder.setDistancePerPulse((Math.PI * kWheelDiameterInch) / kCountsPerRevolution);


Accessing Encoder Values

There are other things we can configure on an encoder. Here are some examples:

// Configures the encoder to consider itself stopped after .1 seconds
encoder.setMaxPeriod(0.1);

// Configures the encoder to consider itself stopped when its rate is below 10
encoder.setMinRate(10);

// Reverses the direction of the encoder
encoder.setReverseDirection(true);

// Can be between 1 and 127 samples
encoder.setSamplesToAverage(5);

//resets the encoder distance to 0 (can be used at any time in code)
encoder.reset();

After configuring the encoder, you can access its values, such as distance traveled, the length of a period, and more!

Getting Encoder Distance

One of the most useful data you can get from an encoder that's so important it needs its own subcategory is the distance traveled. This is accessed through the getDistance() method. This method returns a double and has no parameters. Here is an example with both the m_leftEncoder and m_rightEncoder:

double leftDistance = m_leftEncoder.getDistance()
double rightDistance = m_rightEncoder.getDistance();

If you want to reset the encoder's distance, you can simply do:

encoder.reset()

There are other data that encoders can return, such as the motor's velocity (using the distance traveled per pulse), if the motor stopped, and its hopes and dreams. Here are the method syntaxes below:

/* Gets the current speed of the 
motor in (set distance unit) per second */
double rate = encoder.getRate();

// Gets whether the encoder is stopped
boolean = encoder.getStopped();

// Gets the current period of the encoder
double period = encoder.getPeriod();

If you want to know more about periods and pulses, check the link below.

https://www.motioncontroltips.com/what-are-pulses-per-revolution-for-encoders/


Challenge: The moveDistance() Method

Now that you know how to use an encoder, let's make a new method called moveDistance at the bottom of the RomiDrivetrain class.

Conditions:

Hint #1

You'll only need to use one of the two encoders to calculate the distance. Having two would end up being somewhat redundant.

Hint #2

Try to use either the command's execute() or the subsystem's periodic() function

Answer Code
/*Example goDistance method (parameter names can vary
This method is in the subsystem. Sample code for a command version is in
the other tab. */

private double distance = 0;

// filler things

public void moveDistance(double leftSpeed, double rightSpeed, double newDistance){
    distance = newDistance
}

// code that you want

public void periodic() {
    if (encoder.getDistance() < distance) {
        moveMotors(lSpeed, rSpeed);
        
    } else {
        moveMotors(0, 0);
        
        /* if you want to, you can create a debounce variable
        * that gets activated if you call the moveDistance() method, and
        * resets the speed (google up debounce variable)
        */
    }
}

Answer Code (alternate)
/*Example goDistance method (parameter names can vary
This method is in the subsystem. Sample code for a command version is in
the other tab. */

private double distance = 0;
private RomiDrivetrain subsystem = RomiDrivetrain:GetInstance()

// filler things

// [stuff]
public void execute() {
    // getRightDistanceInch() works too
    if (subsystem.getLeftDistanceInch() < distance) {
        moveMotors(lSpeed, rSpeed);
        
    } else {
        moveMotors(0, 0);
        
        /* if you want to, you can create a debounce variable
        * that gets activated if you call the moveDistance() method, and
        * resets the speed (google up debounce variable)
        */
    }
}

public void isFinished() {
    // once this returns true, this returns true, making 
    // command scheduler end the command
    return (subsystem.getLeftDistanceInch() >= distance);
}

Before using the method, remember to reset the encoder values.

Last updated