DC Motor with Encoder
- Arduino L293D Motor Speed Measurement Using LM393 Encoder
- Overview
This practical measures the **RPM (revolutions per minute)** of a geared DC motor using an **LM393 optical encoder module** and an **Arduino**.
The encoder disc is mounted on the **gearbox output shaft** and contains **20 slots**.
> **20 encoder pulses = 1 complete output-shaft revolution**
The motor is driven using an **L293D motor driver**, while the encoder pulse signal is connected to Arduino digital pin **D2** and measured using an external interrupt.
---
- 1. Hardware Required
| Component | Quantity | | -------------------- | ----------: | | Arduino | 1 | | Geared DC Motor | 1 | | L293D Motor Driver | 1 | | LM393 Encoder Module | 1 | | Encoder Disc | 1 | | Jumper Wires | As required | | Motor Power Supply | 1 |
---
- 2. Pin Connections
- Encoder
| LM393 Encoder | Arduino | | ------------- | ------- | | DO | D2 | | VCC | 5V | | GND | GND |
The encoder's **DO (Digital Output)** generates a pulse whenever an encoder slot passes the sensor.
---
- L293D Motor Driver
| L293D | Arduino | | ----- | ------- | | EN1 | D5 | | IN1 | D7 | | IN2 | D8 |
The motor direction used in this program is:
```text IN1 = HIGH IN2 = LOW ```
Motor speed is controlled using PWM on **EN1 (D5)**.
---
- 3. System Operation
```text
┌─────────────────┐
│ Arduino │
│ │
│ D5 ─────────────┼──── EN1
│ D7 ─────────────┼──── IN1
│ D8 ─────────────┼──── IN2
│ │
│ D2 ◄────────────┼──── LM393 DO
└────────┬────────┘
│
│ PWM / Direction
▼
┌─────────────┐
│ L293D │
└──────┬──────┘
│
▼
┌─────────────┐
│ DC Motor │
│ + Gearbox │
└──────┬──────┘
│
▼
┌─────────────┐
│ Encoder │
│ 20 slots │
└──────┬──────┘
│
│ 20 pulses/rev
▼
Arduino D2
```
---
- 4. RPM Measurement Principle
The encoder disc contains:
- 20 slots per revolution**
Therefore:
```text 1 revolution = 20 pulses ```
The Arduino counts the number of encoder pulses received during a fixed measurement period.
In this program:
```text Measurement time = 1 second ```
The RPM is calculated using:
$$ RPM = \frac{Pulses \times 60} {Slots\ per\ revolution \times Measurement\ time\ (seconds)} $$
Since the measurement period is 1 second:
$$ RPM = \frac{Pulses \times 60}{20} $$
- Example
If the Arduino detects **100 pulses in 1 second**:
$$ RPM = \frac{100 \times 60}{20} $$
$$ RPM = 300 $$
Therefore:
> **100 pulses in one second = 300 RPM**
---
- 5. Encoder Interrupt
The encoder signal is connected to **D2**.
D2 is configured as an external interrupt:
```cpp attachInterrupt(
digitalPinToInterrupt(ENCODER_PIN), encoderISR, RISING
); ```
Every **RISING edge** of the encoder signal calls:
```cpp encoderISR() ```
The pulse counter is then incremented:
```cpp pulseCount++; ```
This allows the Arduino to count encoder pulses without continuously checking the encoder inside `loop()`.
---
- 6. Pulse Filtering
The code includes a minimum pulse interval:
```cpp
- define MIN_PULSE_INTERVAL_US 2000
```
This corresponds to:
```text 2000 µs = 2 ms ```
If another pulse arrives within 2 ms of the previous accepted pulse, it is ignored.
This helps prevent unwanted multiple counts caused by noise or very fast signal transitions.
---
- 7. Motor Control
The motor speed is controlled using PWM:
```cpp int motorPWM = 150; ```
The PWM value is applied to EN1:
```cpp analogWrite(EN1, motorPWM); ```
The motor direction is set using:
```cpp digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); ```
Therefore:
```text EN1 → Speed IN1/IN2 → Direction ```
---
- 8. Complete Arduino Program
```cpp /*
Encoder disc:
20 slots
Encoder location:
Gearbox OUTPUT shaft
Therefore:
20 pulses = 1 output-shaft revolution
Encoder:
LM393 DO -> Arduino D2
Motor driver:
L293D
EN1 -> D5
IN1 -> D7
IN2 -> D8
- /
- define ENCODER_PIN 2
- define EN1 5
- define IN1 7
- define IN2 8
- define SLOTS_PER_REV 20
- define MIN_PULSE_INTERVAL_US 2000
- define SAMPLE_TIME_MS 1000
volatile unsigned long pulseCount = 0; volatile unsigned long lastPulseTime = 0;
int motorPWM = 150;
// ENCODER INTERRUPT void encoderISR() {
unsigned long currentTime = micros();
if ((currentTime - lastPulseTime) >= MIN_PULSE_INTERVAL_US)
{
pulseCount++;
lastPulseTime = currentTime;
}
}
void setup() {
Serial.begin(115200);
pinMode(ENCODER_PIN, INPUT);
pinMode(EN1, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT);
// Motor direction digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW);
// Motor speed analogWrite(EN1, motorPWM);
// Encoder interrupt attachInterrupt( digitalPinToInterrupt(ENCODER_PIN), encoderISR, RISING );
Serial.println("RPM");
}
void loop() {
static unsigned long lastMeasurement = 0;
unsigned long currentTime = millis();
if (currentTime - lastMeasurement >= SAMPLE_TIME_MS)
{
unsigned long pulses;
noInterrupts(); pulses = pulseCount; pulseCount = 0; interrupts();
float rpm =
(pulses * 60.0) /
(SLOTS_PER_REV * (SAMPLE_TIME_MS / 1000.0));
Serial.print("Pulses ");
Serial.print(pulses);
Serial.print(",RPM ");
Serial.println(rpm);
lastMeasurement = currentTime; }
} ```
---
- 9. Serial Monitor Output
Set the Serial Monitor baud rate to:
```text 115200 baud ```
Example output:
```text RPM Pulses 80,RPM 240.00 Pulses 82,RPM 246.00 Pulses 81,RPM 243.00 Pulses 83,RPM 249.00 ```
The first value is the number of encoder pulses detected during the measurement interval.
The second value is the calculated output-shaft speed.
---
- 10. Important Parameters
| Parameter | Value | Function | | ----------------------- | ------: | ----------------------------- | | `ENCODER_PIN` | 2 | Encoder signal input | | `EN1` | 5 | Motor PWM | | `IN1` | 7 | Motor direction | | `IN2` | 8 | Motor direction | | `SLOTS_PER_REV` | 20 | Encoder pulses per revolution | | `MIN_PULSE_INTERVAL_US` | 2000 µs | Pulse filtering | | `SAMPLE_TIME_MS` | 1000 ms | RPM measurement interval | | `motorPWM` | 150 | Motor PWM value |
---
- 11. Signal Flow
```text Motor rotates
↓
Gearbox output shaft rotates
↓
20-slot encoder disc rotates
↓
LM393 detects slots
↓
Digital pulses generated
↓
Arduino D2 interrupt
↓
Pulse counting
↓
1-second measurement
↓
RPM calculation
↓
Serial Monitor ```
---
- 12. Key Point
Because the encoder is mounted on the **gearbox output shaft**, the measured RPM represents the **actual output-shaft RPM**, not the motor's internal shaft RPM.
```text 20 pulses
↓
1 output revolution
↓
Pulse count
↓
RPM ```
- Result:** Arduino controls the geared motor through the L293D and simultaneously measures its output-shaft speed using the LM393 encoder.