Membangun Robot Line Follower 5-Channel dengan Kendali PID & Rute Kustom
Pelajari cara merakit, memprogram, dan men-tuning robot pengikut garis cerdas yang mampu melewati persimpangan rumit serta mendeteksi garis Start dan Finish secara otomatis.
1. Konsep & Arsitektur
Robot Line Follower (Pengikut Garis) ini menggunakan Arduino Nano sebagai otak pemroses. Berbeda dengan robot dasar yang hanya berbelok patah-patah, robot ini menggunakan algoritma PID (Proportional, Integral, Derivative).
P (Proportional)
Bereaksi terhadap error saat ini. Semakin jauh robot dari garis tengah, semakin kuat ia akan berbelok kembali.
I (Integral)
Mengumpulkan histori error. Berguna untuk mengatasi lintasan miring/tidak rata (Sering diset 0 untuk line follower).
D (Derivative)
Memprediksi error masa depan. Berfungsi sebagai "rem" untuk mencegah robot bergetar (osilasi) berlebihan saat kembali ke tengah.
2. Alat, Bahan & Wiring
Daftar Komponen
- 1x Arduino Nano & Kabel USB
- 1x Modul Driver Motor L298N
- 1x Modul Sensor IR 5-Channel (TCRT5000/BFD-1000)
- 2x Motor DC + Gearbox + Roda
- 1x Roda Bebas (Caster Wheel) & Sasis Robot
- 1x Baterai LiPo 2S (7.4V) atau 2x 18650
- Kabel Jumper secukupnya & Saklar On/Off
Tabel Koneksi (Wiring)
| Komponen A | Pin | Komponen B | Pin |
|---|---|---|---|
| Baterai (+) | Merah | L298N | 12V |
| Baterai (-) | Hitam | L298N & Arduino | GND (Common) |
| L298N | 5V Out | Arduino | 5V In |
| Sensor 5-Ch | S1, S2, S3, S4, S5 | Arduino | A0, A1, A2, A3, A4 |
| L298N (Kendali) | ENA, IN1..IN4, ENB | Arduino | D5, D6, D7, D8, D9, D10 |
*Pastikan jumper 5V enable pada L298N terpasang jika menggunakan L298N untuk memberi daya ke Arduino.*
3. Simulator Logika Sensor
Pahami bagaimana letak garis di bawah robot memengaruhi nilai error. Klik kotak sensor di bawah ini untuk mensimulasikan garis hitam (warna gelap) dan latar putih (warna terang).
Hasil Pembacaan CPU
4. Script Arduino Master
Script ini mengintegrasikan PID, manajemen rute persimpangan, dan deteksi Start/Finish otomatis. Copy kode ini dan paste di Arduino IDE.
Penjelasan Bagian Fitur Cerdas:
- Pengaturan Rute:
rute[]menyimpan instruksi arah (1=Kiri, 2=Kanan, 0=Lurus).totalHitammelacak posisi garis Start/Cabang/Finish. - Auto-Kalibrasi: Karena sensor tidak memiliki potensiometer, script menggunakan
analogRead()untuk mencari batas nilai (threshold) warna hitam dan putih secara otomatis setiap kali robot dinyalakan.
// ======================================================
// LINE FOLLOWER 5 CH - PID, MULTI-BRANCH, START & FINISH
// ======================================================
// --- Pin Driver Motor L298N ---
#define ENA 5
#define IN1 6
#define IN2 7
#define IN3 8
#define IN4 9
#define ENB 10
// --- Pin Sensor IR 5-Channel ---
#define S1 A0
#define S2 A1
#define S3 A2
#define S4 A3
#define S5 A4
// --- Pengaturan Rute & Logika Jalur ---
// 1 = Belok Kiri, 2 = Belok Kanan, 0 = Lurus
int rute[] = {1, 2};
int indexCabang = 0; // Penunjuk rute saat ini
int jumlahCabangDiTengah = 2; // Total persimpangan di array rute
int totalHitam = 0; // Penghitung garis hitam tebal
// --- Variabel Kalibrasi Otomatis (Analog) ---
int sensorPins[5] = {S1, S2, S3, S4, S5};
int sensorMin[5] = {1023, 1023, 1023, 1023, 1023};
int sensorMax[5] = {0, 0, 0, 0, 0};
int threshold[5];
// --- Variabel Kecepatan & PID ---
int baseSpeed = 100;
int maxSpeed = 200;
float Kp = 15.0, Ki = 0.0, Kd = 10.0;
float error = 0, previous_error = 0, PID_value = 0;
bool robotBerhenti = false;
void setup() {
pinMode(13, OUTPUT); // LED bawaan Arduino untuk indikator kalibrasi
pinMode(ENA, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT); pinMode(ENB, OUTPUT);
pinMode(S1, INPUT); pinMode(S2, INPUT); pinMode(S3, INPUT);
pinMode(S4, INPUT); pinMode(S5, INPUT);
// --- PROSES AUTO KALIBRASI SENSOR (4 DETIK) ---
digitalWrite(13, HIGH); // LED Menyala: Tanda kalibrasi dimulai
for (int i = 0; i < 400; i++) {
for (int j = 0; j < 5; j++) {
int val = analogRead(sensorPins[j]);
if (val > sensorMax[j]) sensorMax[j] = val;
if (val < sensorMin[j]) sensorMin[j] = val;
}
delay(10);
}
// Menghitung titik tengah antara hitam dan putih
for (int j = 0; j < 5; j++) {
threshold[j] = (sensorMax[j] + sensorMin[j]) / 2;
}
digitalWrite(13, LOW); // LED Mati: Kalibrasi selesai
delay(2000); // Jeda 2 detik sebelum robot siap jalan
}
void loop() {
if (robotBerhenti) {
stopRobot();
return;
}
bacaSensor();
hitungPID();
kontrolMotor();
}
void bacaSensor() {
// Mengubah sinyal Analog menjadi Digital dengan membandingkan Threshold
// *Catatan: Jika sensor Anda membaca putih sebagai nilai tinggi, ubah tanda '>' menjadi '<'
int s1 = analogRead(S1) > threshold[0] ? 1 : 0;
int s2 = analogRead(S2) > threshold[1] ? 1 : 0;
int s3 = analogRead(S3) > threshold[2] ? 1 : 0;
int s4 = analogRead(S4) > threshold[3] ? 1 : 0;
int s5 = analogRead(S5) > threshold[4] ? 1 : 0;
// Menggabungkan nilai 5 sensor menjadi 1 nilai biner menggunakan bitshift
int binerSensor = (s1 << 4) | (s2 << 3) | (s3 << 2) | (s4 << 1) | s5;
// KONDISI KHUSUS & LOGIKA PID MENGGUNAKAN PERCABANGAN (SWITCH-CASE)
switch (binerSensor) {
// SEMUA HITAM ATAU NOISE LEBAR (Diasumsikan sebagai Garis Start, Cabang, atau Finish)
case 0b11111: case 0b11110: case 0b01111: case 0b11101:
case 0b10111: case 0b11100: case 0b11010: case 0b10100:
case 0b00111: case 0b01011: case 0b00101: case 0b11001:
case 0b10110: case 0b10010: case 0b10011: case 0b01101:
case 0b01001: case 0b01110: case 0b11011: case 0b10101:
case 0b10001: case 0b01010:
totalHitam++;
if (totalHitam == 1) { // A. GARIS START
error = 0;
majuDikit();
}
else if (totalHitam > 1 && indexCabang < jumlahCabangDiTengah) { // B. CABANG
int arah = rute[indexCabang];
if (arah == 1) error = -5; // Kiri
else if (arah == 2) error = 5; // Kanan
else error = 0; // Lurus
indexCabang++;
majuDikit();
}
else { // C. FINISH
robotBerhenti = true;
}
break;
// LOGIKA PID NORMAL (Mengikuti Garis)
case 0b10000: error = -4; break;
case 0b11000: error = -3; break;
case 0b01000: error = -2; break;
case 0b01100: error = -1; break;
case 0b00100: error = 0; break;
case 0b00110: error = 1; break;
case 0b00010: error = 2; break;
case 0b00011: error = 3; break;
case 0b00001: error = 4; break;
// LOGIKA KELUAR JALUR (Semua Putih) -> 00000
case 0b00000:
if (previous_error < 0) error = -5; else error = 5;
break;
// SAFETY CATCH-ALL (Praktik baik, meskipun 32 kemungkinan sudah tertulis)
default:
error = previous_error;
break;
}
}
void hitungPID() {
float P = error;
float I = I + error;
float D = error - previous_error;
PID_value = (Kp * P) + (Ki * I) + (Kd * D);
previous_error = error;
}
void kontrolMotor() {
int leftSpeed = baseSpeed + PID_value;
int rightSpeed = baseSpeed - PID_value;
leftSpeed = constrain(leftSpeed, -200, maxSpeed);
rightSpeed = constrain(rightSpeed, -200, maxSpeed);
moveMotor(leftSpeed, rightSpeed);
}
void moveMotor(int left, int right) {
if (left >= 0) { digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); }
else { digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH); }
if (right >= 0) { digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW); }
else { digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH); }
analogWrite(ENA, abs(left)); analogWrite(ENB, abs(right));
}
void majuDikit() {
moveMotor(baseSpeed, baseSpeed);
delay(200); // Waktu lompatan garis tebal
}
void stopRobot() {
digitalWrite(IN1, LOW); digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW); digitalWrite(IN4, LOW);
analogWrite(ENA, 0); analogWrite(ENB, 0);
}
5. Panduan Tuning PID & Kalibrasi
Mengisi kode saja tidak cukup. Kemampuan motor, tingkat pantulan cahaya di ruangan, dan sasis setiap robot berbeda. Anda wajib melakukan langkah-langkah berikut.
Kalibrasi Sensor Manual (Penting!)
Saat saklar robot pertama kali dinyalakan, LED pada Arduino (pin 13) akan menyala selama 4 detik. Dalam rentang waktu ini, pegang robot dan geser bagian sensornya ke kiri dan kanan secara menyilang melewati garis hitam dan latar putih berulang-ulang. Arduino sedang belajar merekam kondisi cahaya ruangan Anda. Setelah LED mati, letakkan robot tepat di atas garis Start, ia akan mulai melaju dalam 2 detik.
Setel Awal (Ground Zero)
Ubah nilai di kode menjadi Kp = 5.0; Ki = 0.0; Kd = 0.0;. Pastikan robot berjalan di atas lintasan. Jika ia tidak merespon tikungan dan keluar jalur, naikkan nilai Kp (misal 10, 15, 20).
Atasi Gemetar (Osilasi)
Jika nilai Kp sudah pas untuk berbelok, robot biasanya akan "menggeleng" keras ke kiri dan kanan. Untuk menghaluskannya (mengerem efek Kp), naikkan nilai Kd sedikit demi sedikit (misal 5, 10, 15).
Kalibrasi Delay Persimpangan
Perhatikan variabel delay(200); di dalam fungsi majuDikit(). Jika robot berhenti sebelum mencapai Finish (karena salah mengira garis persimpangan sebagai garis finish), Naikkan delay. Jika robot sering kelewatan persimpangan tanpa belok, Turunkan delay.
Penjelasan Logika Flow
- Garis Start: Saat robot baru dinyalakan dan berada di atas garis hitam penuh (semua sensor 1), variabel
totalHitammenjadi 1. Robot menjalankan fungsimajuDikit(). Ini "memaksa" robot keluar dari garis start selama 0,2 detik sehingga ia masuk ke mode PID biasa. - Cabang di Tengah: Jika robot ketemu garis hitam penuh lagi, dan kita masih punya rute di array
rute[], robot akan mengambil instruksi (belok kiri/kanan) lalumajuDikit()lagi agar tidak membaca garis yang sama berulang-ulang. - Garis Finish: Jika
totalHitamsudah melebihi jumlah cabang yang didaftarkan, robot akan menganggap garis hitam penuh berikutnya adalah Finish dan memicurobotBerhenti = true.
Cara Menentukan Rute
Jika lintasan Anda adalah: START → Belok Kiri → Belok Kanan → FINISH.
Maka settingannya adalah:
int rute[] = {1, 2};
int jumlahCabangDiTengah = 2;
Jika lintasan Anda hanya: START → FINISH (tanpa cabang).
Maka settingannya adalah:
int rute[] = {};
int jumlahCabangDiTengah = 0;
Tips Tuning Tambahan
Jika robot berhenti sebelum benar-benar sampai finish (karena membaca garis cabang sebagai finish), naikkan nilai delay(200) pada fungsi majuDikit(). Sebaliknya, jika robot melewatkan cabang, kecilkan nilainya.