Skip to main content

Lesson 10.1: Reading Raw Tick Counts with getCurrentPosition()


Why Encoders Beat Timers

If you have ever written code like "run the motor for 2 seconds then stop," you have already run into the core problem: the robot goes a different distance every single run. Battery charge, carpet friction, and wheel slippage all change how far the robot actually travels in that 2 seconds. Encoders solve this by measuring real physical rotation instead of guessing from time.

Every motor shaft has a small magnetic or optical sensor inside it that generates pulses as the shaft turns. The Control Hub counts those pulses and stores the total as an integer called the tick count. When you call getCurrentPosition(), you get that count back. Because it measures rotation rather than elapsed time, it is usually more repeatable than timing alone, but it still cannot see wheel slip, backlash, loose couplers, or a mechanism that stalls before the motor shaft moves as expected.

Encoder Measurement Flow
A
Shaft rotatesThe motor output shaft turns with the mechanism.
B
Pulses generatedThe encoder sensor produces counts as it spins.
C
Hub counts ticksThe Control Hub accumulates the count as an integer.
D
Code reads positiongetCurrentPosition() returns the current tick count.
E
Robot logic uses itYour code converts ticks into distance, angle, or mechanism position.
Official reference

Check the SDK API when you need the exact behavior of DcMotor, DcMotor.RunMode, or getCurrentPosition(): FTC RobotCore Javadocs.

Common robot failure: "the encoder is counting but the mechanism is not moving"

That usually means the motor shaft is rotating while the real mechanism is disconnected, slipping, or jammed. Watch the mechanism, mark the shaft with tape, and compare telemetry to physical motion before assuming the code is wrong.


How the Tick Count Actually Works

Think of the encoder like an odometer that never resets on its own. Every time the motor shaft spins forward, the number goes up. Every time it spins backward, the number goes down. That direction is tied directly to whatever you set with setDirection(). Reversing the motor also flips which way the encoder counts.

The number itself is fairly meaningless without knowing your motor's resolution, which is how many ticks happen per full revolution of the output shaft. A REV HD Hex Motor at a 20:1 gear ratio has a resolution of 537.7 ticks per revolution. A 40:1 version has 1120. You will use that number in the next lesson to convert ticks into real distances.

One thing to note: getCurrentPosition() returns an int, and it starts accumulating from the moment the Robot Controller powers on. It does not zero out automatically between OpMode runs, so if you ran a program earlier in the day the count might already be at 3000 when you start. Lesson 10.5 covers how to reset it properly before each move.


Annotated Code

package org.firstinspires.ftc.teamcode;

import com.qualcomm.robotcore.eventloop.opmode.OpMode;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.hardware.DcMotor;

@TeleOp(name="Encoder_Monitor_Demo")
public class EncoderMonitorDemo extends OpMode {

private DcMotor arm;

@Override
public void init() {
arm = hardwareMap.get(DcMotor.class, "arm_motor");

// RUN_WITHOUT_ENCODER still reads ticks but does not use them
// for closed-loop speed control. Good for raw monitoring.
arm.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);

telemetry.addData("Status", "Encoder monitoring active");
}

@Override
public void loop() {
arm.setPower(-gamepad1.left_stick_y);

// Ask the encoder for the current accumulated tick count
int currentPos = arm.getCurrentPosition();

telemetry.addData("Raw Ticks", currentPos);
telemetry.addData("Motor Power", arm.getPower());
}
}

What a Production Encoder Wrapper Adds

BunyipsLib obtains a raw position, applies logical direction, accumulates the change since the previous reading, and returns the position relative to its reset value:

public int getPosition() {
int currentPosition;
if (!useCache || cachedPosition == null) {
currentPosition =
(getDirection() == DcMotorSimple.Direction.FORWARD ? 1 : -1)
* position.get();
cachedPosition = currentPosition;
} else {
currentPosition = cachedPosition;
}
accumulation += currentPosition - lastPosition;
if (currentPosition != lastPosition) {
// ... update the velocity estimate and timestamp ...
lastPosition = currentPosition;
}
return accumulation - resetVal;
}

This excerpt is slightly shortened around its velocity estimate. The central idea remains visible: a useful encoder reading may include direction, caching, accumulation, and a software zero, not just one raw integer. Excerpted from BunyipsLib's Encoder.java at a pinned commit under the MIT License.


Fill-in-the-Blank Practice

  1. The getCurrentPosition() method returns a value using the __________ data type.
  2. Ticks accumulate based on the rotation of the motor's internal __________ sensor.
  3. If a motor rotates in the direction defined as REVERSE, the tick count will typically __________.
Show answers
  1. int
  2. encoder
  3. decrement (count downward)

Simulator Challenge

Use the simulator below to complete the encoder monitor. Fill in the missing code so the Driver Station shows the raw tick count and current motor power while you move the slide manually.

Telemark Unit 10.1 Simulator
Loads the lesson-specific Telemark encoder challenge with incomplete starter code for students to finish.
Includes live mechanism feedback, telemetry checks, and encoder-state validation for each lesson concept.

Ready to move on?

Only mark complete if you genuinely understand the material. Your progress will be saved in this browser.

Stuck on this lesson?

Ask about anything on this page. It can see which lesson you have open and which part you are reading.