Zbotic Logo Zbotic Logo
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

  • Shop
  • About Us
  • Contact Us
  • Reseller
  • Blogs
020 69134444
1800 209 0998
[email protected]
Help Desk
Facebook Twitter Instagram Linkedin YouTube
Zbotic Logo Zbotic Logo
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

All departments
  • 3D Print Service
  • 3D Printer
  • Batteries & Chargers
  • Development Boards
  • Drone Parts
  • EBike parts
  • Sensor Modules
  • Electronic Components
  • Electronic Modules
  • IoT and Wireless
  • Mechanical Parts and Workbench Tools
  • Motors & Drivers & Pumps & Actuators
  • DIY and Robot Kits
  • Show more
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
Return to previous page
Home Sensors & Modules

Optical Encoder Disc: Speed Measurement with Arduino PWM

Optical Encoder Disc: Speed Measurement with Arduino PWM

March 11, 2026 /Posted byJayesh Jain / 0

Speed measurement is one of the most fundamental requirements in robotics, motor control, and industrial automation. Whether you are building a self-balancing robot, a CNC machine, or a conveyor belt monitor, knowing how fast a motor shaft is spinning is critical. The optical encoder disc combined with an infrared (IR) break-beam sensor is one of the most affordable and accurate ways to measure RPM with an Arduino.

In this comprehensive guide, you will learn everything from how optical encoder discs work to complete Arduino code that uses PWM-compatible interrupt pins to calculate precise speed in real time. By the end, you will have a working tachometer project you can adapt for any motor.

Table of Contents

  1. What Is an Optical Encoder Disc?
  2. How Optical Speed Sensing Works
  3. Types of Encoder Discs
  4. Components Required
  5. Wiring the Encoder Sensor to Arduino
  6. Arduino Code for RPM Measurement
  7. Generating PWM Output Based on Speed
  8. Calibration and Accuracy Tips
  9. Real-World Applications
  10. Troubleshooting Common Issues
  11. Recommended Sensors from Zbotic
  12. Frequently Asked Questions

What Is an Optical Encoder Disc?

An optical encoder disc — also called a slotted wheel or chopper wheel — is a thin circular disk with evenly spaced holes or slots cut around its perimeter. When this disc is mounted on a rotating shaft and placed between an infrared emitter and receiver pair, each slot that passes through the beam generates a digital pulse. By counting these pulses over time, you can calculate the angular velocity (RPM) of the shaft.

The disc itself is passive — it is just a physical interrupt mechanism. The intelligence comes from your Arduino counting the pulses using hardware interrupts and converting the count to meaningful speed data. Encoder discs come in standard slot counts: 20 slots per revolution is the most common for hobbyist use, but you will also find 12, 16, 36, and custom-count versions depending on the resolution you need.

How Optical Speed Sensing Works

The sensing assembly consists of three parts working together:

  • IR LED (emitter): Constantly emits an infrared beam across a small gap.
  • Phototransistor or photodiode (receiver): Normally receives the IR beam and keeps its output HIGH (or LOW depending on module design).
  • Encoder disc: Rotates between the emitter and receiver. Each opaque tooth blocks the beam; each slot allows the beam through.

As the motor spins, the disc interrupts the IR beam repeatedly. Each complete revolution produces a number of pulses equal to the slot count. A 20-slot disc produces 20 rising edges per revolution. By measuring the time between pulses — or by counting pulses in a fixed time window — the Arduino can calculate RPM.

RPM Formula using pulse count method:

RPM = (pulseCount / slotsPerRevolution) * (60 / timeWindowSeconds)

RPM Formula using pulse period method (more accurate at high speeds):

RPM = 60,000,000 / (pulseIntervalMicroseconds * slotsPerRevolution)

Types of Encoder Discs

Not all encoder discs are identical. Understanding the variations helps you pick the right one for your project:

1. Standard Slotted Disc (20 or 24 slots)

The most common. Compatible with LM393-based IR break-beam modules. Gives ±3 RPM accuracy at speeds above 100 RPM. Ideal for DC motor speed control.

2. High-Resolution Disc (100+ slots)

Used in servo drives and precision positioning. Requires faster interrupt handling. The Arduino Uno can handle up to ~50 kHz interrupt rate, so keep slot count within safe limits for your maximum motor speed.

3. Reflective Encoder Disc

Instead of slots, uses alternating black and white stripes. Paired with a reflective IR sensor (like TCRT5000). Easier to mount on the face of a shaft where you cannot thread a disc onto the shaft tip.

4. Magnetic Encoder Disc

Not optical, but worth mentioning. Uses Hall effect sensors. More resistant to dust and oil — common in industrial motors. Not covered in this guide.

Components Required

  • Arduino Uno / Nano / Mega
  • IR optical speed sensor module (FC-03 or equivalent with LM393 comparator)
  • 20-slot encoder disc (usually included with FC-03 modules)
  • DC motor with mounting shaft (or any rotating mechanism)
  • 16×2 LCD display or Serial Monitor for output
  • 10kΩ resistors x 2 (for LCD contrast, optional)
  • Jumper wires and breadboard
  • 5V power supply (USB or battery pack)

The FC-03 IR speed sensor module is the standard choice. It includes the LM393 voltage comparator which converts the analog phototransistor signal into a clean digital output — no extra filtering needed.

Wiring the Encoder Sensor to Arduino

The FC-03 module has four pins: VCC, GND, DO (digital output), and AO (analog output). For interrupt-based speed measurement, use the DO pin.

FC-03 Pin Arduino Pin Notes
VCC 5V Module operates at 3.3–5V
GND GND Common ground
DO Pin 2 (INT0) Must be interrupt-capable pin
AO A0 (optional) Only needed for analog thresholding

Important: On Arduino Uno, only pins 2 and 3 support hardware interrupts (INT0 and INT1). On Arduino Mega, pins 2, 3, 18, 19, 20, and 21 support interrupts. Always use a hardware interrupt pin for encoder signals — polling in loop() will miss pulses at high RPM.

Position the encoder disc between the IR emitter and receiver gap. The disc should rotate freely without touching either side. Adjust the LM393 sensitivity potentiometer until the onboard LED blinks steadily as the disc rotates.

Arduino Code for RPM Measurement

The following code uses the RISING interrupt trigger to count pulses. RPM is calculated every second using the pulse count method. Serial output displays the result.

// Optical Encoder RPM Measurement
// Encoder disc: 20 slots per revolution
// Sensor output connected to Arduino Pin 2 (INT0)

const int ENCODER_PIN = 2;     // Interrupt-capable pin
const int SLOTS = 20;          // Slots per revolution on encoder disc
const int SAMPLE_MS = 1000;    // RPM calculation interval in ms

volatile unsigned long pulseCount = 0;
unsigned long lastSampleTime = 0;
float rpm = 0;

void IRAM_ATTR encoderISR() {
  pulseCount++;
}

void setup() {
  Serial.begin(9600);
  pinMode(ENCODER_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(ENCODER_PIN), encoderISR, RISING);
  Serial.println("Optical Encoder Speed Monitor");
  Serial.println("-----------------------------");
}

void loop() {
  unsigned long currentTime = millis();
  
  if (currentTime - lastSampleTime >= SAMPLE_MS) {
    // Disable interrupt temporarily to read pulse count safely
    detachInterrupt(digitalPinToInterrupt(ENCODER_PIN));
    
    unsigned long count = pulseCount;
    pulseCount = 0;
    
    // Re-enable interrupt
    attachInterrupt(digitalPinToInterrupt(ENCODER_PIN), encoderISR, RISING);
    
    // Calculate RPM
    // count = pulses in SAMPLE_MS milliseconds
    // RPM = (pulses / slots) * (60000 / SAMPLE_MS)
    rpm = ((float)count / SLOTS) * (60000.0 / SAMPLE_MS);
    
    Serial.print("Pulse Count: ");
    Serial.print(count);
    Serial.print(" | RPM: ");
    Serial.println(rpm, 1);
    
    lastSampleTime = currentTime;
  }
}

Upload this sketch and open the Serial Monitor at 9600 baud. Spin the motor and you should see RPM values updating every second.

Generating PWM Output Based on Speed

One powerful application is using measured RPM to control motor speed via PWM — a simple closed-loop controller. Here is an expanded version that reads a target RPM from a potentiometer and adjusts motor PWM to match:

const int MOTOR_PWM_PIN = 9;   // PWM-capable pin
const int POT_PIN = A1;        // Potentiometer for target RPM
const int MAX_RPM = 3000;      // Maximum motor RPM at full PWM

int motorPWM = 0;

void loop() {
  // Read target RPM from potentiometer
  int potVal = analogRead(POT_PIN);  // 0-1023
  float targetRPM = map(potVal, 0, 1023, 0, MAX_RPM);
  
  unsigned long currentTime = millis();
  if (currentTime - lastSampleTime >= SAMPLE_MS) {
    // ... (same RPM calculation as above)
    
    // Proportional control: adjust PWM based on error
    float error = targetRPM - rpm;
    motorPWM += (int)(error * 0.05);  // Proportional gain = 0.05
    motorPWM = constrain(motorPWM, 0, 255);
    analogWrite(MOTOR_PWM_PIN, motorPWM);
    
    Serial.print("Target: "); Serial.print(targetRPM, 0);
    Serial.print(" | Actual: "); Serial.print(rpm, 0);
    Serial.print(" | PWM: "); Serial.println(motorPWM);
    
    lastSampleTime = currentTime;
  }
}

This is a basic P-controller. For better performance, implement a full PID controller using the PID_v1 library available in the Arduino Library Manager.

Calibration and Accuracy Tips

1. Verify Slot Count

Physical slot counts can vary. Count slots manually on your disc before programming. A 20-slot disc will produce 20 pulses per revolution exactly — any mismatch in code gives proportional RPM error.

2. Debounce is Not Usually Needed

The LM393 comparator in the FC-03 module produces a clean digital signal. Software debounce actually hurts accuracy at high RPM. If you are using a raw phototransistor (no comparator), add a 100ns hardware filter capacitor.

3. Increase Sample Rate for Low RPM

At very low RPM (below 30), a 1-second window may not capture any complete revolution. Increase SAMPLE_MS to 2000ms or use the period-measurement method (measure time between successive pulses with micros()).

4. Interrupt Latency

Arduino Uno’s interrupt latency is approximately 3–5 microseconds. At 3000 RPM with a 20-slot disc, pulses arrive every 1ms — well within the safe interrupt response window.

5. Mechanical Alignment

The IR emitter-receiver gap is typically 3–5mm wide. Position the disc centrally. Off-center mounting causes missing pulses when disc wobble exits the beam path.

Real-World Applications

DC Motor Speed Control

Used in line-following robots, RC vehicles, and conveyor systems to maintain constant speed regardless of load changes. The encoder provides feedback to a PID controller driving the motor PWM.

Fan RPM Monitoring

CPU coolers and industrial exhaust fans use encoder-based tachometers to detect bearing failure (sudden RPM drop) and trigger alarms.

Odometry in Mobile Robots

By placing encoder discs on both drive wheels, a robot can estimate distance traveled and direction change. 20-slot discs on 65mm wheels give approximately 1cm resolution per pulse.

Flow Meters

A small paddle wheel with an encoder disc placed in a pipe measures liquid flow rate. Each revolution corresponds to a fixed volume of liquid passing through.

CNC Axis Positioning

Combined with limit switches, optical encoders verify that stepper motors have not skipped steps during rapid moves — a critical safety feature in CNC routers.

Troubleshooting Common Issues

RPM Always Shows Zero

  • Check that the DO pin is connected to an interrupt-capable pin (2 or 3 on Uno).
  • Verify digitalPinToInterrupt() is used — not a raw interrupt number.
  • Test the sensor alone: cover and uncover the gap with paper and check if the LED on the module toggles.

RPM Values Are Erratic or Too High

  • The sensitivity potentiometer may be too sensitive — adjust it until the signal is clean.
  • Check for mechanical vibration causing the disc to bounce in and out of the beam.
  • Ensure disc is rotating freely and not wobbling.

RPM Reads Exactly Double

  • You are likely triggering on both RISING and FALLING edges. Change interrupt mode to RISING only.

Inconsistent Readings at High RPM

  • Increase the interrupt service routine efficiency — remove any Serial.print from the ISR.
  • Consider switching to the Arduino Mega for higher interrupt throughput.

Recommended Sensors from Zbotic

While your optical encoder project is underway, you will find these complementary sensors from Zbotic invaluable for related measurement tasks:

30A Range Current Sensor Module ACS712

30A Range Current Sensor Module ACS712

Measure motor current draw alongside RPM to compute real-time motor power consumption — essential for efficiency monitoring in motor control projects.

View on Zbotic

CJMCU-219 INA219 I2C Power Monitoring Module

CJMCU-219 INA219 I2C Power Monitoring Module

Bi-directional current and power monitoring over I2C — pair with your encoder-based RPM measurement for a complete motor efficiency logger.

View on Zbotic

5A Range Current Sensor Module ACS712

5A Range Current Sensor Module ACS712

Ideal for small DC motors and hobby robots — measures up to 5A with 185mV/A sensitivity, perfect for protecting motors from overcurrent at measured RPMs.

View on Zbotic

Frequently Asked Questions

Q: Can I use the optical encoder disc with ESP32 or Raspberry Pi?

Yes. The ESP32 has hardware interrupt support on most GPIO pins and a built-in PCNT (Pulse Counter) peripheral that is far more accurate than software counting. On Raspberry Pi, use the GPIO.RISING edge callback in Python’s RPi.GPIO library, though timing accuracy is limited by the OS scheduler — consider using a dedicated Arduino or RP2040 for high-accuracy pulse counting.

Q: What is the maximum RPM I can measure with a 20-slot disc and Arduino Uno?

The Arduino Uno can handle interrupts up to approximately 50,000 per second. At 20 slots per revolution, the maximum measurable RPM is (50,000 / 20) × 60 = 150,000 RPM — far beyond any DC motor you would use with an Arduino. In practice, motor speed and disc wobble at high RPM are the limiting factors, not the Arduino.

Q: How do I measure the direction of rotation?

A single encoder disc cannot determine direction. You need a quadrature encoder — two sets of slots offset by 90 degrees — or two separate sensor modules positioned slightly apart. By comparing which sensor fires first, you can determine CW vs CCW rotation.

Q: Is the FC-03 module the same as the H206 speed sensor?

Functionally yes. Both use LM393 comparators with slotted IR pairs. The H206 typically has a wider slot gap (6mm) suitable for thicker discs, while FC-03 has a 5mm gap. Both work with standard Arduino code without modification.

Q: My encoder disc does not fit my motor shaft. What should I do?

Encoder discs are available in different shaft bore diameters (2mm, 3mm, 4mm, 6mm being common). If yours does not fit, print a custom hub adapter using a 3D printer, or use a flexible coupling sleeve to connect your shaft diameter to the disc bore. Many encoder discs also include a set screw for adjustable mounting.

Q: Can I use encoder data to measure distance instead of speed?

Absolutely. This is called odometry. For a wheel of circumference C mm and a 20-slot disc, each pulse = C/20 mm of travel. Accumulate pulse counts to track total distance. Combine left and right wheel encoders to track 2D position and heading of a mobile robot.

Ready to Build Your Speed Measurement Project?

Zbotic stocks a full range of sensors and modules for Arduino projects across India. From current sensors to LiDAR modules, get everything you need for your next build with fast shipping.

Browse All Sensors at Zbotic

Tags: arduino pwm, optical encoder, rotary encoder, RPM sensor, speed measurement
Share Post
  • Facebook
  • Linkedin
  • Whatsapp
Drone Telemetry Setup: SiK Rad...
blog drone telemetry setup sik radio vs frsky vs expresslrs compared 596108
blog color sensor tcs34725 detect rgb and hex values with arduino 596110
Color Sensor TCS34725: Detect ...

Related posts

Svg%3E
Read more

Encoder Module: Position and Speed Measurement with Arduino

April 1, 2026 0
A rotary encoder converts the angular position and rotation speed of a shaft into electrical signals that Arduino can count... Continue reading
Svg%3E
Read more

Infrared Obstacle Sensor: Line Follower and Object Detection

April 1, 2026 0
Infrared obstacle sensors are the building blocks of line-following robots, edge detection systems, and proximity triggers. These tiny modules emit... Continue reading
Svg%3E
Read more

Rain Sensor and Raindrop Detection Module: Arduino Guide

April 1, 2026 0
A rain sensor module detects the presence of water droplets on its surface, giving Arduino a simple signal to trigger... Continue reading
Svg%3E
Read more

LiDAR Sensor TFmini: Distance Measurement Beyond Ultrasonic

April 1, 2026 0
When ultrasonic sensors hit their limits — range too short, accuracy too coarse, outdoor sunlight causing interference — LiDAR sensors... Continue reading
Svg%3E
Read more

Pressure Sensor BMP280: Weather Station and Altitude Meter

April 1, 2026 0
The BMP280 barometric pressure sensor by Bosch measures atmospheric pressure with ±1 hPa accuracy and temperature with ±1°C precision. These... Continue reading

Add comment Cancel reply

Your email address will not be published. Required fields are marked

Facebook Twitter Instagram Pinterest Linkedin Youtube

Get the latest deals and more.

Download on Google Play Download on the App Store

Call us: 020 69134444 / 1800 209 0998

Monday - Saturday 09:30 AM - 06:00 PM
For Technical Supports Email: [email protected]
For Sales / Enquiries Email: [email protected]

  • My Account

    • Cart

    • Wishlist

    • Checkout

    • My Orders

    • Track Order

    • My Account

  • Information

    • FAQs

    • Blogs

    • Career

    • About Us

    • Contact Us

    • Payment Options

  • Policies

    • Privacy Policy

    • Terms & Conditions

    • GST Input Tax Credit

    • Shipping Return Policy

    • E-Waste Collection Points

    • Our Sitemap

© Zbotic.in is registered trademark of Moxie Supply Pvt Ltd – All Rights Reserved
Login
Use Phone Number
Use Email Address
Not a member yet? Register Now
Reset Password
Use Phone Number
Use Email Address
Register
Already a member? Login Now