Tujuan Tutorial:
Mempelajari bagaimana cara menggunakan sensor optocoupler sebagai sensor kecepatan (RPM) untuk mengontrol motor menggunakan algoritma PID. Mikrokontroler yang digunakan meliputi: Arduino Uno, ESP32, dan Arduino Mega.
Deskripsi Cara Kerja Optocoupler
Optocoupler (disebut juga optoisolator) adalah komponen elektronik yang berfungsi menghubungkan dua rangkaian listrik tanpa koneksi langsung, alias isolasi optik. Komponen ini sering dipakai untuk melindungi rangkaian mikrokontroler dari tegangan tinggi atau gangguan listrik dari perangkat lain (seperti motor, power supply, dsb).
Prinsip Kerja
Optocoupler bekerja dengan mengubah sinyal listrik menjadi cahaya, lalu mengubah kembali cahaya tersebut menjadi sinyal listrik di sisi lain. Di dalamnya terdapat dua bagian utama:
- LED (Light Emitting Diode) – berfungsi sebagai pemancar cahaya.
- Phototransistor (atau photodiode/phototriac) – berfungsi sebagai penerima cahaya.
Ketika arus listrik mengalir ke LED di dalam optocoupler, LED menyala dan memancarkan cahaya.
Cahaya ini diterima oleh phototransistor yang akan mengalirkan arus di sisi sekunder (biasanya terhubung ke mikrokontroler).
Tidak ada koneksi listrik langsung antara kedua sisi, hanya lewat cahaya, makanya disebut isolasi optik.
Contoh Penerapan
- Sebuah piringan berputar dipasang di depan sensor optocoupler, dengan celah/lubang atau garis hitam-putih.
- Saat piringan berputar, cahaya dari LED dipantulkan atau terhalang oleh piringan.
- Phototransistor menerima sinyal ON atau OFF sesuai dengan pantulan itu.
- Tiap perubahan ini dianggap sebagai 1 pulsa → digunakan untuk menghitung kecepatan (RPM) motor.
- Nilai RPM bisa dibandingkan dengan target (setpoint), dan digunakan oleh algoritma PID untuk mengatur kecepatan motor.
Keunggulan Optocoupler
- Menghindari gangguan listrik dari sistem luar
- Melindungi mikrokontroler dari lonjakan tegangan
- Sangat cepat dan responsif
- Cocok untuk sinyal digital seperti deteksi pulsa
Karakteristik Sensor Optocoupler
Sensor optocoupler itu punya sifat-sifat unik yang bikin dia penting banget buat proteksi dan deteksi sinyal. Yuk kita bahas satu per satu karakteristik utamanya:
🌟 1. Isolasi Galvanik
- Tidak ada sambungan listrik langsung antara input dan output.
- Cuma cahaya yang jadi perantaranya.
- Sangat aman untuk memisahkan sirkuit tegangan tinggi dan rendah.
Contohnya: bisa sambungin mikrokontroler ke rangkaian AC tanpa bahaya korslet atau lonjakan listrik!
🌟 2. Kecepatan Respons Tinggi
- Waktu respons (rise time & fall time) cepat.
- Cocok banget untuk deteksi pulsa-pulsa cepat, misalnya buat hitung RPM motor.
🌟 4. Sensitivitas Tinggi
- Bisa mendeteksi perubahan sangat kecil di sisi input.
- Makanya cocok untuk sensor deteksi gerakan, sensor garis, atau sensor kecepatan.
🌟 5. Tegangan & Arus Rendah di Input
- Biasanya bekerja dengan arus kecil (sekitar 5–20 mA) di sisi LED-nya.
- Bisa langsung dikendalikan oleh mikrokontroler seperti Arduino Uno, ESP32, atau Mega.
🌟 6. Kecil dan Ringan
- Bentuknya mungil, bisa dipasang di PCB dengan mudah.
- Cocok untuk aplikasi portable atau compact.
🌟 7. Cocok untuk Sinyal Digital
- Umumnya menghasilkan sinyal HIGH atau LOW (logika digital).
- Makanya cocok banget buat keperluan deteksi pulsa atau kontrol sinyal digital.
🌟 8. Tahan Lama & Anti Noise
- Karena tidak ada kontak fisik, tidak mudah aus.
- Juga tahan terhadap gangguan sinyal (noise listrik) karena isolasinya kuat.
Cara penggunaan menggunakan arduino uno

OUT Optocoupler Pin 2 (Interrupt)
VCC Optocoupler 5V
GND Optocoupler GND
IN1 L298N Pin 8
IN2 L298N Pin 9
ENA L298N Pin 10 (PWM)
VCC L298N 12V (eksternal)
GND L298N GND (sama dengan Arduino)
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <PID_v1.h>
// === Konfigurasi LCD ===
LiquidCrystal_I2C lcd(0x27, 16, 2); // Alamat I2C bisa 0x27 atau 0x3F
// === Pin ===
const int sensorPin = 2; // Pin untuk optocoupler (interrupt)
const int motorPin = 9; // Pin PWM ke motor driver
// === Variabel RPM ===
volatile unsigned long pulseCount = 0;
unsigned long lastTime = 0;
float rpm = 0;
// === PID Variables ===
double setpoint = 300.0; // Target RPM
double input = 0; // RPM aktual
double output = 0; // Output PWM
// PID tunning (ubah sesuai respons sistemmu)
double Kp = 1.5, Ki = 0.8, Kd = 0.1;
PID myPID(&input, &output, &setpoint, Kp, Ki, Kd, DIRECT);
void setup() {
Serial.begin(9600);
lcd.begin();
lcd.backlight();
pinMode(sensorPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(sensorPin), countPulse, FALLING);
pinMode(motorPin, OUTPUT);
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(0, 255); // PWM range
}
void loop() {
unsigned long currentMillis = millis();
// Hitung RPM tiap 1 detik
if (currentMillis - lastTime >= 1000) {
noInterrupts();
unsigned long pulses = pulseCount;
pulseCount = 0;
interrupts();
// Misal 1 pulsa = 1 putaran
rpm = pulses * 60.0; // 60 detik = 1 menit
input = rpm;
myPID.Compute();
analogWrite(motorPin, (int)output);
displayRPM(rpm, output);
lastTime = currentMillis;
}
}
void countPulse() {
pulseCount++;
}
void displayRPM(float rpmValue, float pwmVal) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("RPM: ");
lcd.print((int)rpmValue);
lcd.setCursor(0, 1);
lcd.print("PWM: ");
lcd.print((int)pwmVal);
}
Cara Penggunaan dengan ESP32
ESP32 adalah mikrokontroler yang lebih canggih dengan konektivitas Wi-Fi dan Bluetooth. Dengan ESP32, Anda dapat mengirimkan data ke server atau aplikasi web melalui jaringan
.

Komponen | Pin ESP32 |
---|---|
OUT Optocoupler | Pin 14 (Interrupt) |
VCC Optocoupler | 5V |
GND Optocoupler | GND |
IN1 L298N | Pin 26 |
IN2 L298N | Pin 27 |
ENA L298N | Pin 25 (PWM) |
VCC L298N | 12V (eksternal) |
GND L298N | GND (sama dengan ESP32) |
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <PID_v1.h>
// LCD I2C (0x27 atau 0x3F tergantung modul)
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Pin setup
const int sensorPin = 14; // pin interrupt dari optocoupler
const int motorPWM = 25; // pin PWM output ke motor driver
// RPM variables
volatile unsigned long pulseCount = 0;
unsigned long lastTime = 0;
double rpm = 0;
// PID variables
double setpoint = 300.0; // target RPM
double input = 0;
double output = 0;
double Kp = 1.5, Ki = 0.8, Kd = 0.1;
PID myPID(&input, &output, &setpoint, Kp, Ki, Kd, DIRECT);
void IRAM_ATTR countPulse() {
pulseCount++;
}
void setup() {
Serial.begin(115200);
Wire.begin(21, 22); // SDA, SCL
lcd.begin();
lcd.backlight();
pinMode(sensorPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(sensorPin), countPulse, FALLING);
ledcSetup(0, 1000, 8); // channel 0, freq 1kHz, 8-bit
ledcAttachPin(motorPWM, 0);
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(0, 255);
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - lastTime >= 1000) {
noInterrupts();
unsigned long pulses = pulseCount;
pulseCount = 0;
interrupts();
rpm = pulses * 60.0; // 1 pulsa = 1 putaran
input = rpm;
myPID.Compute();
ledcWrite(0, (int)output);
displayRPM(rpm, output);
lastTime = currentMillis;
}
}
void displayRPM(double rpmVal, double pwmVal) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("RPM: ");
lcd.print((int)rpmVal);
lcd.setCursor(0, 1);
lcd.print("PWM: ");
lcd.print((int)pwmVal);
}
Cara Penggunaan dengan Arduino Mega
Arduino Mega memiliki lebih banyak pin dan lebih banyak port serial dibandingkan dengan Arduino Uno, yang membuatnya lebih fleksibel

.
Komponen | Pin Arduino MEGA |
---|
OUT Optocoupler | Pin 2 (Interrupt) |
VCC Optocoupler | 5V |
GND Optocoupler | GND |
IN1 L298N | Pin 6 |
IN2 L298N | Pin 7 |
ENA L298N | Pin 5 (PWM) |
VCC L298N | 12V (eksternal) |
GND L298N | GND (sama dengan Arduino Mega) |
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <PID_v1.h>
// === LCD I2C setup ===
LiquidCrystal_I2C lcd(0x27, 16, 2); // alamat I2C bisa 0x27 atau 0x3F
// === Pin Setup ===
#define SENSOR_PIN 2 // interrupt pin dari optocoupler (INT4 pada Mega)
#define ENA 9 // PWM ke motor (ENA L298N)
#define IN1 8 // Arah motor
#define IN2 7
// === PID Variables ===
double setpoint = 300.0; // Target RPM
double input = 0;
double output = 0;
double Kp = 1.5, Ki = 0.8, Kd = 0.1;
PID myPID(&input, &output, &setpoint, Kp, Ki, Kd, DIRECT);
// === RPM Calculation ===
volatile unsigned long pulseCount = 0;
unsigned long lastTime = 0;
double rpm = 0;
void setup() {
Serial.begin(9600);
Wire.begin(); // SDA = 20, SCL = 21 pada Mega
lcd.begin();
lcd.backlight();
// Pin setup
pinMode(SENSOR_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(SENSOR_PIN), countPulse, FALLING);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
digitalWrite(IN1, HIGH); // arah default
digitalWrite(IN2, LOW);
pinMode(ENA, OUTPUT);
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(0, 255);
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - lastTime >= 1000) {
noInterrupts();
unsigned long pulses = pulseCount;
pulseCount = 0;
interrupts();
rpm = pulses * 60.0; // misal 1 pulsa = 1 rotasi
input = rpm;
myPID.Compute();
analogWrite(ENA, (int)output); // PWM ke motor
displayData(rpm, output);
lastTime = currentMillis;
}
}
void countPulse() {
pulseCount++;
}
void displayData(double rpmVal, double pwmVal) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("RPM: ");
lcd.print((int)rpmVal);
lcd.setCursor(0, 1);
lcd.print("PWM: ");
lcd.print((int)pwmVal);
}