Panduan · 15 mnt baca

Robot Penghindar Rintangan dengan Arduino: Panduan HC-SR04 dan Servo

Buat robot penghindar rintangan dengan Arduino: HC-SR04 yang memindai di atas servo, pengkabelan L298N atau L293D, logika berhenti-mundur-belok, sensor IR, dan mode manual lewat Bluetooth.

Robot penghindar rintangan adalah mobil robot yang berjalan sendiri, menyadari dinding, kursi, atau kotak di depannya tanpa menabraknya, lalu mencari jalan baru. Rakitan yang paling umum memakai Arduino Uno, sensor jarak ultrasonik HC-SR04, motor servo SG90 yang memutar sensor ke kiri dan kanan, dua motor DC bergearbox, dan driver motor L298N (atau L293D). Robot berjalan lurus, berhenti ketika sudah dekat dengan rintangan, mundur sedikit, menoleh ke kedua sisi untuk mengukur, lalu melanjutkan perjalanan ke arah yang paling lega.

Di panduan ini kita mengubah mobil 2WD dari artikel Mobil Robot Arduino menjadi robot otonom dengan susunan pin yang sama. Langkah demi langkah kita bahas tabel pengkabelan, cara menghitung ambang jarak, kode yang berkembang dalam tiga tahap, permukaan yang tidak terlihat oleh sensor dan cara menutup celah itu dengan sensor inframerah, dan terakhir beralih ke mode manual lewat Bluetooth dari ponselmu. Kode untuk menjalankan robot yang sama dengan ESP32 atau Raspberry Pi Pico ada di akhir artikel.

Sensor jarak ultrasonik HC-SR04
HC-SR04: transduser bertanda T mengirim suara 40 kHz dan yang bertanda R mendengarkan pantulannya. Inilah mata robot penghindar rintangan; ia mengukur 2–400 cm dalam sudut sempit sekitar 15 derajat.

Bagaimana cara kerja robot penghindar rintangan?

Setiap robot otonom mengulang siklus tiga langkah yang sama puluhan kali per detik: merasakan, memutuskan, bertindak. HC-SR04 yang merasakan: ia mengirim suara 40 kHz pendek yang tidak bisa didengar telingamu dan mengukur berapa lama pantulannya kembali; bagi waktu dalam mikrodetik itu dengan 58 dan kamu mendapat jarak dalam sentimeter. Arduino yang memutuskan dengan membandingkan jarak terukur dengan ambang yang kamu tetapkan. L298N dan motor yang bertindak. Karena sensornya terpasang di servo, robot bisa “melihat” ke kiri dan kanan tanpa memutar badannya, jadi keputusan beloknya jauh lebih baik daripada robot dengan sensor yang diam. Detail cara kerja sensor ini ada di artikel Sensor Jarak HC-SR04.

KomponenTugasCatatan
Arduino Uno (atau Nano)Otak: mengukur, memutuskan, dan memerintah motorESP32 atau Pico juga bisa
HC-SR04Mata: mengukur jarak ke rintangan di depanBekerja di 5 V, 2–400 cm
Servo SG90Leher: memutar sensor ke kiri dan kananSensor dipasang ke lengan servo dengan braket plastik
L298N atau shield L293DOtot: memberi arah dan kecepatan ke motorPin Arduino tidak sanggup memberi arus motor
2 motor TT bergearbox dan roda casterDifferential driveBelok dilakukan dengan memutar kedua roda ke arah berlawanan
2 × sel 18650 (7,4 V)DayaBaterai 9 V tidak cukup
2 sensor rintangan IR (opsional)Menangkap rintangan di sudut dan sampingModul berbasis LM393 seperti FC-51
HC-05 (opsional)Kendali manual dari ponselmuHanya bisa dengan Android
Arduino Uno
Arduino Uno
L298N
L298N
Motor TT
Motor TT
Li-ion 18650
Li-ion 18650

Catu daya: jangan biarkan servo me-reset robot

Karena robot penghindar rintangan menambahkan servo ke motor, pembagian daya lebih penting daripada di mobil robot biasa. SG90 menarik sekitar 10 mA ketika diam; begitu mulai bergerak, arusnya melonjak ke 100–250 mA, dan ketika terbebani ia mendekati setengah ampere. Kalau lonjakan ini bersamaan dengan arus start motor, jalur 5 V Arduino anjlok sekejap dan board restart. Solusinya sederhana: motor mendapat daya dari baterai lewat L298N, Arduino dari baterai lewat VIN, sedangkan servo, HC-SR04, sensor IR, dan HC-05 berbagi pin 5V Arduino, dengan kapasitor 470 µF dipasang di dekat kabel catu servo. Bahkan ketika servo bergerak, total beban di jalur 5 V tetap di bawah setengah ampere, dan karena singkat, regulator Uno masih sanggup menanganinya. Untuk menghitung umur baterai dengan angkamu sendiri, pakai alat Umur baterai.

BagianSumber dayaArus umum
2 motor TTTerminal 12V L298N ← 2 × 18650 (7,4 V)0,3–0,6 A ketika berjalan, sampai 2 A ketika start
Arduino UnoVIN ← positif baterai (setelah sakelar)Sekitar 50 mA
Servo SG905V Arduino + kapasitor 470 µF~10 mA ketika diam, 100–250 mA ketika bergerak
HC-SR045V ArduinoSekitar 15 mA
2 sensor IR5V ArduinoMasing-masing 20–40 mA
HC-055V Arduino30–40 mA ketika pairing, sekitar 10 mA ketika terhubung
Hubungkan semua GND jadi satu (negatif baterai, L298N, Arduino, servo, sensor); tanpa ground bersama, sensor membaca jarak yang ngawur dan servo bergetar. Jangan mengalirkan daya servo lewat kabel jumper tipis yang sama dengan motor. Kalau kamu memakai servo yang lebih kuat seperti MG90S atau MG996R, beri daya bukan dari Arduino, tapi dari modul step-down terpisah yang diatur ke 5 V (misalnya LM2596).

Skema pengkabelan: Arduino Uno, ESP32, dan Pico

Pin motornya sama dengan di panduan mobil robot, jadi kamu bisa beralih ke proyek ini hanya dengan menambahkan kepala sensor tanpa membongkar mobilmu. Pin kecepatan sengaja ditaruh di 5 dan 6: di Uno, library Servo memakai Timer1 sehingga mematikan PWM di pin 9 dan 10; kalau kecepatan motor ada di pin itu, kendali kecepatan langsung rusak begitu servo dipasang. HC-SR04 dan sensor IR dipasang di A0–A3. Pin analog Uno juga bisa berfungsi sebagai pin digital 14–19 kalau perlu, dan pilihan ini memudahkan pemakaian kode yang sama dengan shield L293D, karena shield tidak menyentuh pin-pin ini. Susunan pin board-mu bisa kamu lihat di alat Pinout.

KoneksiArduino UnoESP32Raspberry Pi Pico
L298N ENA (kecepatan motor kiri)D5GPIO 25GP15
L298N IN1, IN2D7, D8GPIO 27, 33GP14, GP13
L298N ENB (kecepatan motor kanan)D6GPIO 26GP10
L298N IN3, IN4D9, D4GPIO 32, 4GP12, GP11
Sinyal servo (oranye)D3GPIO 13GP16
Servo + (merah), − (cokelat)5V, GND5V L298N, GND5V L298N, GND
HC-SR04 TRIGA0GPIO 18GP17
HC-SR04 ECHOA1 (langsung)GPIO 19, lewat pembagi 1 kΩ / 2 kΩGP18, lewat pembagi 1 kΩ / 2 kΩ
HC-SR04 VCC5V5V L298N5V L298N
OUT IR kiri, OUT IR kananA2, A3GPIO 23, 22GP19, GP20
VCC sensor IR5V3V33V3
HC-05 TXD, RXDD10, D11 (RXD lewat pembagi)Tidak perlu (Bluetooth bawaan)GP1, GP0 (UART0)
Daya boardVIN ← baterai (setelah sakelar)5V (VIN) ← 5V L298NVSYS ← 5V L298N
Pin ECHO HC-SR04 mengeluarkan sinyal 5 V, sedangkan pin ESP32 dan Pico bekerja di 3,3 V dan tidak tahan 5 V. Buat pembagi tegangan dengan susunan ECHO → 1 kΩ → titik yang menuju board → 2 kΩ → GND: 5 V × 2 / 3 ≈ 3,3 V. TRIG tidak perlu pembagi; sinyal 3,3 V sudah cukup untuk memicu sensor. Di ESP32 dan Pico, board, servo, dan HC-SR04 berbagi output 5V L298N yang sama, jadi kamu bisa mendekati batas sekitar 0,5 A dari regulator kecil itu; kalau terjadi reset, beri daya servo dari sumber 5 V terpisah.

Pasang dan uji kepala sensor

Motor servo mikro SG90
SG90: servo mikro 9 gram yang berputar 60 derajat dalam sekitar 0,1 detik pada 4,8 V. Braket plastik yang memegang HC-SR04 dibaut ke lengan servo.
  1. Hubungkan servo tanpa lengannya dan upload sketch uji di bawah. Di akhir setiap sapuan, kode memutar servo ke 90 derajat dan menunggu 2 detik; cabut kabel USB selama jeda itu dan servo akan diam di posisinya. Pasang lengan ke porosnya sehingga sensor menghadap lurus ke depan; dengan begitu 90 derajat berarti “lurus ke depan”.
  2. Pasang HC-SR04 ke lengan servo dengan braket plastik atau lem tembak. Kabel sensor harus cukup panjang supaya tidak tertarik kencang ketika servo berputar; kabel yang tersangkut di sasis selama sapuan 140 derajat adalah kerusakan yang umum.
  3. Pasang sensor 8–12 cm di atas lantai dan dekat dengan titik paling depan badan robot. Terlalu rendah, ia menangkap pantulan dari lantai dan tekstur karpet; terlalu tinggi, ia tidak bisa melihat rintangan yang rendah.
  4. Miringkan sensor 3–5 derajat ke atas. Sensor yang benar-benar datar dan rendah bisa mengira pantulan dari lantai sebagai rintangan, terutama di lantai yang kasar.
  5. Buka Serial Monitor pada 9600 baud. Kalau kamu melihat nilai kecil di baris 125 dan 160 derajat ketika tanganmu ada di sebelah kiri sensor, sisi kiri adalah sudut-sudut besar; kalau sebaliknya, atur SERVO_DIR ke -1 di sketch lanjutan dan tukar nilai LEFT_ANGLE dan RIGHT_ANGLE di sketch pertama.
C++ (Arduino IDE)
1#include <Servo.h>
2
3const int SERVO_PIN = 3;
4const int TRIG = A0, ECHO = A1;        // analog pinler dijital pin olarak / analog pins used as digital pins
5Servo head;
6
7int pingCm() {
8  digitalWrite(TRIG, LOW);  delayMicroseconds(2);
9  digitalWrite(TRIG, HIGH); delayMicroseconds(10);   // 10 µs tetik darbesi / 10 µs trigger pulse
10  digitalWrite(TRIG, LOW);
11  unsigned long t = pulseIn(ECHO, HIGH, 25000UL);    // en fazla 25 ms bekle (~4,3 m) / wait at most 25 ms (~4.3 m)
12  return t / 58;                                     // 0 = yankı yok / 0 = no echo
13}
14
15void setup() {
16  Serial.begin(9600);
17  pinMode(TRIG, OUTPUT);
18  pinMode(ECHO, INPUT);
19  head.attach(SERVO_PIN);
20  head.write(90);                                    // önce ortala / center first
21  delay(1000);
22}
23
24void loop() {
25  const int angles[] = {20, 55, 90, 125, 160};
26  for (int a : angles) {
27    head.write(a);
28    delay(400);                                      // servo yerine otursun / let the servo settle
29    Serial.print(a);
30    Serial.print(F(" derece / degrees: "));
31    Serial.print(pingCm());
32    Serial.println(F(" cm"));
33  }
34  Serial.println();
35  head.write(90);
36  delay(2000);
37}

Setiap baris menunjukkan satu sudut dan jarak ke arah itu. Kalau tidak ada apa-apa dalam jarak sekitar 4 meter dari sensor, kamu akan membaca 0 cm: pulseIn() mengembalikan 0 kalau tidak ada pantulan dalam 25 ms. Di kode utama kita akan menganggap 0 sebagai “jalan kosong”, tapi sensor dengan kabel longgar atau TRIG dan ECHO yang tertukar biasanya juga membaca 0. Jadi sebelum menaruh robot di lantai, tahan tanganmu di 10, 30, dan 60 cm dan pastikan nilainya benar-benar berubah; robot yang dijalankan tanpa uji ini akan menabrak dinding tanpa melambat.

Algoritma keputusan: berhenti, mundur, belok ke arah yang paling lega

Membagi perilaku robot ke dalam zona berdasarkan jarak membuat kodenya sederhana sekaligus andal. Tanpa rintangan di depan, robot melaju dengan kecepatan penuh, melambat ketika rintangan makin dekat, dan begitu mencapai ambang berhenti, ia berhenti dan memindai. Selama pemindaian, sensor melihat 70 dan 35 derajat ke kiri serta 35 dan 70 derajat ke kanan; di setiap arah diambil tiga pembacaan dan nilai mediannya yang dipakai. Robot berbelok ke arah dengan jarak terpanjang, sebesar sudut itu. Kalau tidak ada arah yang lega, misalnya ketika ia masuk ke sudut ruangan, ia mundur sedikit dan berbelok 180 derajat.

Jarak terukurZonaYang dilakukan robot
Di atas 60 cm (atau tanpa pantulan)KosongMaju dengan kecepatan penuh (PWM 200)
25–60 cmMendekatMelambat sebanding dengan jarak (PWM 200 turun ke 130)
12–25 cmRintanganBerhenti, memastikan pembacaan, memindai ke dua arah, belok ke arah yang paling lega
Di bawah 12 cmTerlalu dekatMundur dulu selama 350 ms, lalu memindai
Semua arah di bawah 35 cmJalan buntuMundur dan berbelok 180 derajat

Ambang-ambang ini tidak dipilih asal-asalan. Jarak berhenti adalah jumlah tiga margin: margin reaksi (jarak yang ditempuh di antara dua pembacaan), margin pengereman (seberapa jauh robot masih meluncur setelah motor diputus), dan margin belok (agar moncongnya tidak menyentuh rintangan ketika berputar di tempat). Mobil dengan motor TT di 6 V melaju sekitar 0,5–0,7 m/dtk dan menempuh 3–4 cm dalam interval pengukuran 60 ms. Margin pengereman sekitar 5 cm, dan untuk badan selebar 15 cm yang berputar di tempat, margin beloknya sekitar 10 cm. Totalnya sekitar 18–20 cm; ditambah beberapa sentimeter margin keamanan, STOP_CM = 25 adalah titik awal yang baik. Kalau robotmu lebih cepat atau lantainya licin, naikkan ambangnya ke 30–35 cm. Sebaliknya, di koridor sempit, ambang yang terlalu besar membuat robot terus berhenti dan memindai, jadi lakukan penyetelan akhir di lintasanmu sendiri.

Kode langkah demi langkah 1: robot penghindar rintangan pertamamu

Versi pertama adalah kerangka algoritmanya: maju, berhenti di 25 cm, mundur, lihat ke kiri dan kanan, belok ke sisi yang lebih lega. Fungsi motor drive(left, right) sama dengan di panduan mobil robot dan menerima nilai dari -255 sampai 255; positif berarti maju, negatif berarti mundur. Setelah meng-upload kode, taruh dulu mobilnya di atas kotak dengan roda tidak menyentuh lantai, lalu perhatikan bagaimana ia berhenti dan berbelok ketika kamu mendekatkan tangan ke sensor; kalau semuanya terlihat benar, taruh robot di lantai.

C++ (Arduino IDE)
1#include <Servo.h>
2
3const int ENA = 5, IN1 = 7, IN2 = 8;            // sol motor / left motor
4const int ENB = 6, IN3 = 9, IN4 = 4;            // sağ motor / right motor
5const int SERVO_PIN = 3;
6const int TRIG = A0, ECHO = A1;
7
8const int STOP_CM = 25;                         // bu mesafede dur / stop at this distance
9const int SPEED = 170;                          // düz gidiş hızı / cruising speed
10const int TURN = 170;                           // dönüş hızı / turning speed
11const int LEFT_ANGLE = 160, RIGHT_ANGLE = 20;   // ters ise yer değiştir / swap if reversed
12
13Servo head;
14
15void drive(int left, int right) {               // her biri -255 … 255 / each -255 … 255
16  digitalWrite(IN1, left > 0);  digitalWrite(IN2, left < 0);
17  digitalWrite(IN3, right > 0); digitalWrite(IN4, right < 0);
18  analogWrite(ENA, abs(left));
19  analogWrite(ENB, abs(right));
20}
21
22int pingCm() {
23  digitalWrite(TRIG, LOW);  delayMicroseconds(2);
24  digitalWrite(TRIG, HIGH); delayMicroseconds(10);
25  digitalWrite(TRIG, LOW);
26  unsigned long t = pulseIn(ECHO, HIGH, 25000UL);
27  if (t == 0) return 400;                       // yankı yok: önü açık say / no echo: treat as open
28  return t / 58;
29}
30
31int lookAt(int angle) {
32  head.write(angle);
33  delay(400);                                   // servo dönsün ve dursun / let the servo turn and settle
34  return pingCm();
35}
36
37void setup() {
38  int pins[] = {ENA, IN1, IN2, ENB, IN3, IN4, TRIG};
39  for (int p : pins) pinMode(p, OUTPUT);
40  pinMode(ECHO, INPUT);
41  drive(0, 0);
42  head.attach(SERVO_PIN);
43  head.write(90);
44  delay(3000);                                  // yere koyman için süre / time to put it on the floor
45}
46
47void loop() {
48  int front = pingCm();
49  if (front > STOP_CM) {
50    drive(SPEED, SPEED);                        // yol açık: ileri / path clear: forward
51    delay(60);                                  // ölçümler arası 60 ms / 60 ms between readings
52    return;
53  }
54
55  drive(0, 0);                                  // 1) dur / 1) stop
56  delay(150);
57  drive(-SPEED, -SPEED);                        // 2) biraz geri çekil / 2) back off a little
58  delay(300);
59  drive(0, 0);
60
61  int left = lookAt(LEFT_ANGLE);                // 3) iki yana bak / 3) look both ways
62  int right = lookAt(RIGHT_ANGLE);
63  head.write(90);
64  delay(300);
65
66  if (left < STOP_CM && right < STOP_CM) {      // iki yan kapalı: geri dön / both blocked: turn around
67    drive(-TURN, TURN);
68    delay(700);
69  } else if (left > right) {                    // 4) daha açık tarafa dön / 4) turn to the more open side
70    drive(-TURN, TURN);
71    delay(350);
72  } else {
73    drive(TURN, -TURN);
74    delay(350);
75  }
76  drive(0, 0);
77  delay(100);
78}

Kode ini menjalankan tugasnya, tapi punya beberapa kelemahan: satu pembacaan yang salah membuat robot berhenti tanpa alasan, ia selalu mendekati rintangan dengan kecepatan yang sama, ia hanya melihat ke dua arah, dan lama beloknya tidak bergantung pada sudut. Selain itu, karena menunggu dengan delay(), ia tidak bisa bereaksi terhadap apa pun selama pemindaian. Detail logika menunggu ada di artikel millis() dan delay(); versi berikutnya memperbaiki sebagian besar masalah ini.

Kode langkah demi langkah 2: filter, perlambatan bertahap, IR, dan Bluetooth

Versi lanjutan bekerja dengan pengkabelan yang sama, dan tidak masalah kalau kamu belum memasang sensor IR dan HC-05. Karena input IR diatur dengan INPUT_PULLUP, sensor yang tidak terhubung terbaca “tidak ada rintangan” (HIGH); tanpa HC-05, robot langsung mulai dalam mode otomatis. Tabel di bawah menjelaskan fungsi setiap bagian kode.

C++ (Arduino IDE)
1#include <Servo.h>
2#include <SoftwareSerial.h>
3
4// Pinler / Pins
5const int ENA = 5, IN1 = 7, IN2 = 8;     // sol motor / left motor
6const int ENB = 6, IN3 = 9, IN4 = 4;     // sağ motor / right motor
7const int SERVO_PIN = 3;
8const int TRIG = A0, ECHO = A1;
9const int IR_LEFT = A2, IR_RIGHT = A3;   // LOW = engel (takılı değilse HIGH) / LOW = obstacle (HIGH if not fitted)
10SoftwareSerial bt(10, 11);               // RX, TX → HC-05 TXD, RXD (RXD bölücüyle / RXD via divider)
11
12// Ayarlar / Settings
13const int BACK_CM = 12;                  // daha yakınsa geri çekil / closer: back off first
14const int STOP_CM = 25;                  // dur ve tara / stop and scan
15const int SLOW_CM = 60;                  // yavaşlamaya başla / start slowing down
16const int GUARD_CM = 15;                 // manuel modda çarpışma koruması / collision guard in manual mode
17const int MAX_CM = 400;
18const int CRUISE = 200, SLOW = 130, TURN = 170;   // PWM hızları / PWM speeds
19const int SERVO_CENTER = 90;             // sensör öne bakmıyorsa düzelt / adjust if not facing ahead
20const int SERVO_DIR = 1;                 // +70 sola bakmıyorsa -1 yap / set to -1 if +70 doesn't look left
21const float MS_PER_DEG = 4.0;            // derece başına ms, kalibre et / ms per degree, calibrate
22const unsigned long BT_TIMEOUT = 600;    // manuelde komut kesilirse dur / stop if commands stop
23
24Servo head;
25bool autoMode = true;
26int manualLeft = 0, manualRight = 0, manualSpeed = 200;
27unsigned long lastCmd = 0, lastPing = 0;
28
29void drive(int left, int right) {        // her biri -255 … 255 / each -255 … 255
30  left = constrain(left, -255, 255);
31  right = constrain(right, -255, 255);
32  digitalWrite(IN1, left > 0);  digitalWrite(IN2, left < 0);
33  digitalWrite(IN3, right > 0); digitalWrite(IN4, right < 0);
34  analogWrite(ENA, abs(left));
35  analogWrite(ENB, abs(right));
36}
37
38int pingCm() {
39  digitalWrite(TRIG, LOW);  delayMicroseconds(2);
40  digitalWrite(TRIG, HIGH); delayMicroseconds(10);
41  digitalWrite(TRIG, LOW);
42  unsigned long t = pulseIn(ECHO, HIGH, 25000UL);  // ~4,3 m zaman aşımı / ~4.3 m timeout
43  return t == 0 ? MAX_CM : (int)(t / 58);          // yankı yok = açık alan / no echo = open space
44}
45
46int distanceCm() {                       // 3 ölçümün ortancası / median of 3 readings
47  int a = pingCm(); delay(60);
48  int b = pingCm(); delay(60);
49  int c = pingCm();
50  return max(min(a, b), min(max(a, b), c));
51}
52
53bool irBlocked(int pin) {
54  return digitalRead(pin) == LOW;
55}
56
57int lookAt(int offset) {                 // + sol, - sağ (derece) / + left, - right (degrees)
58  head.write(SERVO_CENTER + SERVO_DIR * offset);
59  delay(300);                            // servo yerine otursun / let the servo settle
60  return distanceCm();
61}
62
63void turnBy(int deg) {                   // + sola, - sağa / + left, - right
64  if (deg > 0) drive(-TURN, TURN);
65  else drive(TURN, -TURN);
66  delay((unsigned long)(abs(deg) * MS_PER_DEG));
67  drive(0, 0);
68  delay(100);
69}
70
71void avoid() {
72  drive(0, 0);                           // 1) dur / 1) stop
73  delay(120);
74  int front = distanceCm();              // ortancayla doğrula / confirm with the median
75  bool sides = irBlocked(IR_LEFT) || irBlocked(IR_RIGHT);
76  if (front >= STOP_CM && !sides) return;          // yanlış alarm / false alarm
77
78  if (front < BACK_CM || sides) {        // 2) çok yakın: geri çekil / 2) too close: back off
79    drive(-TURN, -TURN);
80    delay(350);
81    drive(0, 0);
82  }
83
84  const int offsets[] = {70, 35, -35, -70};        // 3) tara / 3) scan
85  int bestOffset = 0, bestCm = 0;
86  for (int off : offsets) {
87    int cm = lookAt(off);
88    if (cm > bestCm) { bestCm = cm; bestOffset = off; }
89  }
90  head.write(SERVO_CENTER);
91  delay(200);
92
93  if (bestCm < STOP_CM + 10) {           // her yön kapalı: çıkmaz / every way blocked: dead end
94    drive(-TURN, -TURN);
95    delay(400);
96    turnBy(180);
97  } else {
98    turnBy(bestOffset);                  // 4) en açık yöne dön / 4) turn to the most open direction
99  }
100}
101
102void autoStep() {
103  if (millis() - lastPing < 60) return;  // 60 ms'de bir ölç / measure every 60 ms
104  lastPing = millis();
105  int d = pingCm();
106  bool l = irBlocked(IR_LEFT), r = irBlocked(IR_RIGHT);
107
108  if (d < STOP_CM || (l && r)) {
109    avoid();
110  } else if (l) {                        // sol köşede engel: sağa kaç / front-left: dodge right
111    drive(TURN, -TURN);
112    delay(150);
113  } else if (r) {                        // sağ köşede engel: sola kaç / front-right: dodge left
114    drive(-TURN, TURN);
115    delay(150);
116  } else if (d < SLOW_CM) {
117    int s = map(d, STOP_CM, SLOW_CM, SLOW, CRUISE);   // yaklaştıkça yavaşla / slow down as you get closer
118    drive(s, s);
119  } else {
120    drive(CRUISE, CRUISE);
121  }
122}
123
124void manualStep() {
125  if (millis() - lastCmd > BT_TIMEOUT) {           // komut yok: dur / no commands: stop
126    manualLeft = 0;
127    manualRight = 0;
128  }
129  static int front = MAX_CM;
130  if (millis() - lastPing >= 60) {
131    lastPing = millis();
132    front = pingCm();
133  }
134  bool forward = manualLeft > 0 && manualRight > 0;
135  if (forward && front < GUARD_CM) drive(0, 0);    // çarpışma koruması / collision guard
136  else drive(manualLeft, manualRight);
137}
138
139void handleBluetooth() {
140  while (bt.available()) {
141    char c = bt.read();
142    Serial.println(c);                   // gelen harfi göster / show the incoming letter
143    lastCmd = millis();
144    if (c == 'A') {                      // otomatik mod / auto mode
145      autoMode = true;
146      continue;
147    }
148    if (c == 'M') {                      // manuel mod / manual mode
149      autoMode = false;
150      manualLeft = manualRight = 0;
151      drive(0, 0);
152      head.write(SERVO_CENTER);
153      continue;
154    }
155    if (autoMode) continue;              // otomatikte yön harflerini yok say / ignore in auto mode
156    int s = manualSpeed;
157    switch (c) {
158      case 'F': manualLeft = s;  manualRight = s;  break;   // ileri / forward
159      case 'B': manualLeft = -s; manualRight = -s; break;   // geri / backward
160      case 'L': manualLeft = -s; manualRight = s;  break;   // yerinde sola / spin left
161      case 'R': manualLeft = s;  manualRight = -s; break;   // yerinde sağa / spin right
162      case 'S': manualLeft = 0;  manualRight = 0;  break;   // dur / stop
163      default:
164        if (c >= '0' && c <= '9') manualSpeed = map(c - '0', 0, 9, 100, 240);   // hız kademesi / speed level
165    }
166  }
167}
168
169void setup() {
170  int outs[] = {ENA, IN1, IN2, ENB, IN3, IN4, TRIG};
171  for (int p : outs) pinMode(p, OUTPUT);
172  drive(0, 0);
173  pinMode(ECHO, INPUT);
174  pinMode(IR_LEFT, INPUT_PULLUP);
175  pinMode(IR_RIGHT, INPUT_PULLUP);
176  Serial.begin(9600);
177  bt.begin(9600);                        // HC-05 veri modu hızı / HC-05 data mode baud rate
178  head.attach(SERVO_PIN);
179  head.write(SERVO_CENTER);
180  delay(3000);                           // yere koyman için süre / time to put it on the floor
181}
182
183void loop() {
184  handleBluetooth();
185  if (autoMode) autoStep();
186  else manualStep();
187}
Fungsi atau pengaturanFungsinya
pingCm()Mengambil satu pembacaan; mengembalikan 400 cm (ruang kosong) kalau tidak ada pantulan dalam 25 ms
distanceCm()Mengambil 3 pembacaan berjarak 60 ms dan mengembalikan mediannya; membuang satu nilai pencilan
autoStep()Mengukur setiap 60 ms; berdasarkan jarak dan sensor IR, robot terus melaju, melambat, mengelak, atau memanggil avoid()
avoid()Berhenti, memastikan pembacaan, mundur kalau perlu, melihat ke 4 arah, dan berbelok ke arah yang paling lega
turnBy(degrees)Memutar robot di tempat sebesar sudut yang diberikan; lamanya dihitung dengan MS_PER_DEG
manualStep()Menjalankan arah yang dikirim dari ponsel; berhenti di 15 cm ketika maju, berhenti kalau tidak ada perintah selama 600 ms
SERVO_CENTER, SERVO_DIRSudut ketika sensor menghadap lurus ke depan dan arah mana yang kiri
STOP_CM, SLOW_CM, BACK_CMAmbang berhenti, melambat, dan mundur

Untuk robot penghindar rintangan, filter median lebih unggul daripada rata-rata: untuk tiga pembacaan seperti 24, 26, dan 400 cm, rata-ratanya 150 cm dan menyesatkan robot, sedangkan median memilih 26 cm. Kalau ingin mendalaminya, lihat artikel memfilter data sensor. Pembagian mode otomatis dan manual sebenarnya juga state machine kecil; pendekatan ini kami jelaskan secara detail di panduan state machine Arduino. Setelah meng-upload kode, setel robot sesuai ruanganmu dengan urutan ini:

  1. Titik tengah servo: Dengan robot menghadap tegak lurus ke dinding datar, kalau sensor tidak menunjuk lurus ke dinding itu, ubah SERVO_CENTER sedikit demi sedikit, misalnya ke 85 atau 95.
  2. Lama belok: Untuk sementara tambahkan baris turnBy(360); di akhir setup() dan perhatikan apakah robot berputar penuh. Kalau ia berputar 300 derajat dan bukan 360, atur MS_PER_DEG ke 4.0 × 360 / 300 = 4.8. Karena nilai ini berubah tergantung baterai dan lantai, setel dengan baterai penuh di lantai tempat robot akan berjalan.
  3. Ambang berhenti: Arahkan robot ke dinding dan ukur seberapa jauh moncongnya dari dinding ketika ia berhenti. Kalau kurang dari 10 cm, naikkan STOP_CM sebesar 5 cm.
  4. Kecepatan lambat: Kalau SLOW di bawah ambang start motor, robot macet di zona mendekat; dalam hal itu, naikkan SLOW ke 150.

Titik buta HC-SR04: permukaan lunak, dinding miring, dan rintangan tipis

Sensor ultrasonik melihat permukaan yang memantulkan suara dengan baik, tapi tidak semua rintangan mengembalikan suara ke sensor. Pabrikan menyarankan target minimal 0,5 m² yang sedatar mungkin untuk hasil yang baik. Padahal di ruangan sungguhan, robot bertemu gorden, sofa, kaki kursi, dan sudut dinding. Suara memantul dengan sudut yang sama seperti datangnya, mirip bola biliar: sensor yang menghadap dinding secara tegak lurus mendapat pantulan yang kuat, tapi kalau garis pandangnya menyimpang lebih dari sekitar 30–40 derajat dari tegak lurus, suaranya terpantul ke arah lain dan tidak pernah kembali. Dalam kasus itu pulseIn() mengembalikan 0 dan kode mengira jalannya kosong. Inilah alasan paling umum robot menyerempet dinding.

Rintangan atau permukaanKenapa tidak terlihatSolusi
Gorden, sofa, bantal, pakaian, bulu hewan peliharaanPermukaan lunak dan berpori menyerap suara dan pantulannya kembali sangat lemahTambahkan sensor IR untuk jarak dekat dan jalankan robot pelan-pelan
Mendekati dinding dengan sudut miringSuara terpantul menjauh dan pantulannya tidak sampai ke sensorTambahkan sensor IR yang dimiringkan ke luar di sudut depan dan pindai dengan sudut yang lebih rapat
Kaki kursi dan meja, tiang tipisPermukaan pemantulnya sangat kecil dan pantulannya lemahTurunkan kecepatan, pakai filter median, tambahkan sensor IR di samping
Rintangan rendah di bawah sensor (kabel, ambang pintu, sandal)Berada di bawah kerucut suaraTambahkan sensor IR yang menghadap ke bawah atau microswitch di bumper depan
Tepi meja, lubang tanggaSensor ultrasonik menghadap ke depan dan tidak bisa melihat celah di lantaiDeteksi jurang dengan TCRT5000 yang menghadap lantai
Benda yang lebih dekat dari 2 cmZona mati sensor: pantulan kembali sebelum semburan suaranya selesaiAtur robot agar mundur di 12 cm
Sudut ruangan dan koridor sempitSuara memantul di antara dua dinding dan kembali terlambat, jadi jaraknya tampak lebih jauhFilter median dan pembacaan dari beberapa sudut
Menutup apa yang tidak terlihat oleh satu sensor dengan sensor lain selalu lebih efektif daripada berusaha membuat satu sensor sempurna. Tapi langkah pertamamu sebaiknya memperlambat robot: robot yang melaju 0,3 m/dtk tidak menabrak sekeras robot yang melaju 0,7 m/dtk setelah pembacaan salah yang sama, dan masih ada waktu untuk pembacaan kedua. Kelebihan dan kekurangan berbagai sensor jarak sudah kami kumpulkan di artikel perbandingan sensor jarak Arduino.

Menambahkan sensor IR

Sensor ultrasonik dan inframerah (IR) saling menutup kelemahan masing-masing. Sensor rintangan IR seperti FC-51 terdiri dari LED inframerah dan penerima; ketika cahaya pantulannya cukup kuat, komparator LM393 menarik output ke LOW dan LED di board menyala. Jangkauannya bisa diatur dengan trimpot dari sekitar 2 sampai 30 cm, tapi sensor ini tidak mengukur jarak, ia hanya bilang “ada rintangan” atau “tidak ada rintangan”. Kalau kamu memasang dua sensor IR di sudut depan robot, dimiringkan 30–45 derajat ke luar, keduanya menangkap kaki kursi dan dinding miring yang berada di luar kerucut sempit sensor ultrasonik. Di kode lanjutan, robot mengelak sebentar ke kanan ketika IR kiri terpicu dan ke kiri ketika IR kanan terpicu; kalau keduanya terpicu bersamaan, ia berhenti dan memindai seolah-olah ada rintangan di depan.

FiturHC-SR04 (ultrasonik)FC-51 (rintangan IR)TCRT5000 (pantulan IR)
OutputJarak (cm)Ya / tidak (digital)Nilai analog dan output digital
Jangkauan2–400 cmSekitar 2–30 cm (bisa diatur)Sekitar 1–15 mm
Sudut deteksiSekitar 15°Sekitar 35°Sangat sempit
Titik lemahPermukaan lunak, miring, dan tipisPermukaan hitam dan doff, sinar matahariPerubahan ketinggian, sinar matahari
Melihat dengan baikKaca, benda hitam, permukaan datar yang luasKain, sudut, rintangan dekatWarna lantai dan tepi meja
Posisi di robotMata utama, disapukan oleh servoSudut depanDi bawah bumper depan, menghadap lantai
Sensor pantulan inframerah TCRT5000
TCRT5000: dipasang menghadap ke bawah, 5–10 mm di atas lantai, sensor ini menyadari tepi meja dan lubang tangga; begitu pantulannya hilang, robot bisa berhenti dan mundur.

Untuk robot yang berkeliling di atas meja, rintangan paling berbahaya justru jurang. Kalau kamu memasang modul TCRT5000 yang menghadap lantai di bawah bumper depan, kamu langsung tahu begitu lantai di bawahnya hilang. Hubungkan output digital modul ke D2, yang masih kosong di Uno; cek dulu di Serial Monitor ke level mana output-nya berubah ketika tidak ada lantai, lalu baca pin ini di bagian paling awal autoStep() dan, kalau lantainya hilang, hentikan motor seketika dan mundurkan robot. Pengecekan ini harus didahulukan sebelum pengukuran jarak; jatuh selalu lebih mahal daripada menabrak.

Beralih ke mode manual lewat Bluetooth

Kadang kamu ingin mengemudikan robot otonom ini dengan tangan: memindahkannya dari satu ruangan ke ruangan lain, membawanya ke depan rintangan untuk menguji reaksinya, atau sekadar bermain. Koneksi HC-05 di kode lanjutan memungkinkan hal itu. Ketika ponsel mengirim huruf A, robot beralih ke mode otomatis; ketika mengirim M, ia beralih ke mode manual. Di mode manual dipakai huruf kendali dari panduan mobil robot (F, B, L, R, S), dengan satu perbedaan: kalau robot melihat rintangan lebih dekat dari 15 cm ketika maju, ia berhenti meskipun ada perintahmu. Pelindung tabrakan ini membuatmu tetap mendapat manfaat dari sensor robot otonom ketika mengemudi manual. Langkah pairing HC-05 dan perintah AT ada di artikel Modul Bluetooth HC-05.

HurufAksiDi mode apa?
ABeralih ke mode otomatisKedua mode
MBeralih ke mode manual, hentikan robotKedua mode
F / BMaju / mundurManual
L / RBerputar di tempat ke kiri / kananManual
SBerhentiManual
0–9Level kecepatan (PWM 100–240)Manual
  1. Hubungkan pin TXD HC-05 ke D10, pin RXD-nya ke D11 lewat pembagi 1 kΩ / 2 kΩ, VCC ke 5V, dan GND ke GND.
  2. Pair HC-05 di pengaturan Bluetooth ponsel Android-mu dengan PIN 1234 (atau 0000 kalau gagal).
  3. Instal aplikasi remote mobil Bluetooth dari Play Store dan hubungkan ke HC-05. Kalau Arduino tetap terhubung ke USB dan kamu membuka Serial Monitor pada 9600 baud, kode akan mencetak setiap huruf yang datang dari ponsel.
  4. Kebanyakan aplikasi remote punya tombol tambahan seperti lampu atau klakson, dan masing-masing mengirim hurufnya sendiri. Cari huruf-huruf itu di Serial Monitor lalu ganti 'A' dan 'M' di kode dengannya; kalau kamu lebih suka menentukan tombolnya sendiri, kamu bisa membuat remote sendiri dengan panduan App Inventor Arduino Bluetooth.
  5. Cabut kabel USB dan nyalakan sakelar; setelah 3 detik robot mulai berjalan dalam mode otomatis. Beralihlah ke mode manual dan kemudikan dari ponselmu.
Di Uno, SoftwareSerial menahan interrupt lain selama sekitar 1 ms ketika menerima satu byte; selama itu pulsa library Servo bisa memanjang dan kepala sensor mungkin sedikit berkedut. Ini tidak memengaruhi perilaku robot, tapi kalau mengganggumu, kamu bisa beralih ke Bluetooth bawaan ESP32. HC-05 dan HC-06 tidak bisa dipakai dengan iPhone; untuk iPhone kamu butuh modul BLE atau ESP32 yang diprogram untuk BLE.

Membuatnya dengan motor shield L293D

Shield driver motor L293D
Motor shield L293D: langsung ditancapkan ke Arduino Uno; empat motor DC dihubungkan ke terminal M1–M4 dan dua servo ke header di sudutnya.

Kalau kamu tidak suka kabel yang semrawut, kamu bisa memakai motor shield L293D (Adafruit Motor Shield V1 dan klonnya) yang langsung ditancapkan ke Arduino Uno sebagai pengganti L298N. Shield ini bisa mengendalikan empat motor DC, punya dua header servo, dan memberi daya servo dari jalur 5 V Arduino. Motornya tidak dihubungkan langsung ke pin Arduino, tapi lewat shift register 74HC595 di board, jadi kamu mengendalikannya dengan library Adafruit Motor Shield (yang untuk V1, bukan V2), yaitu AFMotor, yang diinstal dari Library Manager. Shield ini memakai D3, D4, D5, D6, D7, D8, D11, dan D12 untuk motor serta D9 dan D10 untuk servo; A0–A5, D2, dan D13 tetap kosong. Karena HC-SR04 dan sensor IR sudah ada di A0–A3, kamu hanya perlu mengubah kode motor, pin servo, dan pin HC-05.

PengaturanDengan L298NDengan shield L293D
Koneksi motorTerminal OUT1–OUT4Terminal M1 (kiri) dan M2 (kanan)
Kode motordigitalWrite dan analogWrite di dalam drive()AFMotor di dalam drive()
SERVO_PIN39 atau 10, tergantung header tempat servo ditancapkan
HC-05D10, D11A4 (RX) dan A5 (TX): SoftwareSerial bt(A4, A5)
Arus per kanal2 A kontinu0,6 A kontinu, puncak 1,2 A
Daya motorTerminal 12VTerminal EXT_PWR; dengan jumper PWR terpasang, Arduino mendapat daya dari catu yang sama
C++ (Arduino IDE)
1// L293D shield: ENA–IN4 tanımlarını ve setup()'taki pinMode listesinden bu pinleri sil, drive() fonksiyonunu aşağıdakiyle değiştir
2// L293D shield: delete the ENA–IN4 definitions, remove them from the pinMode list in setup() and replace drive() with the one below
3// Ayrıca / Also: SERVO_PIN = 9 ya da / or 10, SoftwareSerial bt(A4, A5)
4#include <AFMotor.h>                     // Adafruit Motor Shield V1 kütüphanesi / library
5
6AF_DCMotor leftMotor(1);                 // M1 klemensi / M1 terminal
7AF_DCMotor rightMotor(2);                // M2 klemensi / M2 terminal
8
9void drive(int left, int right) {        // her biri -255 … 255 / each -255 … 255
10  leftMotor.setSpeed(min(abs(left), 255));
11  rightMotor.setSpeed(min(abs(right), 255));
12  leftMotor.run(left > 0 ? FORWARD : (left < 0 ? BACKWARD : RELEASE));
13  rightMotor.run(right > 0 ? FORWARD : (right < 0 ? BACKWARD : RELEASE));
14}

Batas 0,6 A per kanal pada L293D cukup untuk mengemudikan robot 2WD dengan motor TT secara normal, tapi ketika roda mendorong rintangan dan macet, motor bisa menarik lebih dari 1 A dan chip-nya cepat panas. Karena itu algoritma pemindaian yang menghentikan robot sebelum menekan rintangan juga memperpanjang umur shield. Pengaturan jumper shield dan sketch mobil empat motor ada di artikel Motor Shield L293D, dan cara kerja L298N di panduan Mengendalikan Motor DC dengan L298N.

Robot penghindar rintangan dengan ESP32

Ada dua perbedaan penting di ESP32. Pertama, library Servo Arduino tidak bisa dipakai di ESP32, jadi kita membuat sinyal servo langsung dengan LEDC, unit PWM board ini: pada sinyal 50 Hz, pulsa 0,544–2,4 ms sama dengan 0–180 derajat. Karena motor bekerja di 1 kHz dan servo di 50 Hz, kanal motor diatur lebih dulu dan kanal servo setelahnya, sehingga servo mendapat timer sendiri. Kedua, ESP32 sudah punya Bluetooth klasik bawaan, jadi HC-05 tidak diperlukan; robot muncul di ponsel sebagai “BlueGrays-Robot” dan huruf arah serta mode sama dengan versi Uno. Kodenya untuk versi 3.x dari ESP32 Arduino core (ledcAttach dan ledcWrite bekerja dengan nomor pin), dan karena butuh Bluetooth klasik, kode ini tidak bisa dikompilasi untuk ESP32-S3 atau ESP32-C3.

C++ (Arduino IDE)
1// ESP32 Arduino çekirdeği 3.x / ESP32 Arduino core 3.x
2#include "BluetoothSerial.h"
3
4const int ENA = 25, IN1 = 27, IN2 = 33;   // sol motor / left motor
5const int ENB = 26, IN3 = 32, IN4 = 4;    // sağ motor / right motor
6const int SERVO_PIN = 13;
7const int TRIG = 18, ECHO = 19;           // ECHO 1 kΩ / 2 kΩ bölücüyle / ECHO via a 1 kΩ / 2 kΩ divider
8const int IR_LEFT = 23, IR_RIGHT = 22;    // LOW = engel / LOW = obstacle
9
10const int BACK_CM = 12, STOP_CM = 25, SLOW_CM = 60, GUARD_CM = 15, MAX_CM = 400;
11const int CRUISE = 200, SLOW = 130, TURN = 170;
12const int SERVO_CENTER = 90, SERVO_DIR = 1;
13const float MS_PER_DEG = 4.0;             // kalibre et / calibrate
14
15BluetoothSerial bt;
16bool autoMode = true;
17int manualLeft = 0, manualRight = 0;
18unsigned long lastCmd = 0, lastPing = 0;
19
20void drive(int left, int right) {         // her biri -255 … 255 / each -255 … 255
21  left = constrain(left, -255, 255);
22  right = constrain(right, -255, 255);
23  digitalWrite(IN1, left > 0);  digitalWrite(IN2, left < 0);
24  digitalWrite(IN3, right > 0); digitalWrite(IN4, right < 0);
25  ledcWrite(ENA, abs(left));
26  ledcWrite(ENB, abs(right));
27}
28
29void servoWrite(int angle) {              // 0–180° → 544–2400 µs
30  angle = constrain(angle, 0, 180);
31  uint32_t us = map(angle, 0, 180, 544, 2400);
32  ledcWrite(SERVO_PIN, us * 16384 / 20000);   // 14 bit, 20 ms periyot / 14-bit, 20 ms period
33}
34
35int pingCm() {
36  digitalWrite(TRIG, LOW);  delayMicroseconds(2);
37  digitalWrite(TRIG, HIGH); delayMicroseconds(10);
38  digitalWrite(TRIG, LOW);
39  unsigned long t = pulseIn(ECHO, HIGH, 25000UL);
40  return t == 0 ? MAX_CM : (int)(t / 58);
41}
42
43int distanceCm() {                        // 3 ölçümün ortancası / median of 3 readings
44  int a = pingCm(); delay(60);
45  int b = pingCm(); delay(60);
46  int c = pingCm();
47  return max(min(a, b), min(max(a, b), c));
48}
49
50bool irBlocked(int pin) { return digitalRead(pin) == LOW; }
51
52void turnBy(int deg) {                    // + sola, - sağa / + left, - right
53  if (deg > 0) drive(-TURN, TURN);
54  else drive(TURN, -TURN);
55  delay((unsigned long)(abs(deg) * MS_PER_DEG));
56  drive(0, 0);
57  delay(100);
58}
59
60void avoid() {
61  drive(0, 0);
62  delay(120);
63  int front = distanceCm();
64  bool sides = irBlocked(IR_LEFT) || irBlocked(IR_RIGHT);
65  if (front >= STOP_CM && !sides) return;            // yanlış alarm / false alarm
66  if (front < BACK_CM || sides) {                    // geri çekil / back off
67    drive(-TURN, -TURN);
68    delay(350);
69    drive(0, 0);
70  }
71  const int offsets[] = {70, 35, -35, -70};
72  int bestOffset = 0, bestCm = 0;
73  for (int off : offsets) {
74    servoWrite(SERVO_CENTER + SERVO_DIR * off);
75    delay(300);
76    int cm = distanceCm();
77    if (cm > bestCm) { bestCm = cm; bestOffset = off; }
78  }
79  servoWrite(SERVO_CENTER);
80  delay(200);
81  if (bestCm < STOP_CM + 10) {                       // çıkmaz / dead end
82    drive(-TURN, -TURN);
83    delay(400);
84    turnBy(180);
85  } else {
86    turnBy(bestOffset);
87  }
88}
89
90void setup() {
91  int outs[] = {IN1, IN2, IN3, IN4, TRIG};
92  for (int p : outs) pinMode(p, OUTPUT);
93  pinMode(ECHO, INPUT);
94  pinMode(IR_LEFT, INPUT_PULLUP);
95  pinMode(IR_RIGHT, INPUT_PULLUP);
96  ledcAttach(ENA, 1000, 8);               // motor PWM: 1 kHz, 8 bit
97  ledcAttach(ENB, 1000, 8);
98  ledcAttach(SERVO_PIN, 50, 14);          // servo: 50 Hz, 14 bit
99  drive(0, 0);
100  servoWrite(SERVO_CENTER);
101  bt.begin("BlueGrays-Robot");            // telefonda görünecek ad / name shown on the phone
102  delay(3000);
103}
104
105void loop() {
106  while (bt.available()) {
107    char c = bt.read();
108    lastCmd = millis();
109    if (c == 'A') autoMode = true;                                  // otomatik / auto
110    else if (c == 'M') {                                            // manuel / manual
111      autoMode = false;
112      manualLeft = manualRight = 0;
113      servoWrite(SERVO_CENTER);
114    }
115    else if (!autoMode) {
116      if (c == 'F')      { manualLeft = 200;  manualRight = 200; }  // ileri / forward
117      else if (c == 'B') { manualLeft = -200; manualRight = -200; } // geri / backward
118      else if (c == 'L') { manualLeft = -200; manualRight = 200; }  // sola / left
119      else if (c == 'R') { manualLeft = 200;  manualRight = -200; } // sağa / right
120      else if (c == 'S') { manualLeft = 0;    manualRight = 0; }    // dur / stop
121    }
122  }
123
124  if (millis() - lastPing < 60) return;               // 60 ms'de bir / every 60 ms
125  lastPing = millis();
126  int d = pingCm();
127
128  if (!autoMode) {
129    if (millis() - lastCmd > 600) manualLeft = manualRight = 0;     // komut yok: dur / no command: stop
130    bool forward = manualLeft > 0 && manualRight > 0;
131    if (forward && d < GUARD_CM) drive(0, 0);                       // çarpışma koruması / collision guard
132    else drive(manualLeft, manualRight);
133    return;
134  }
135
136  bool l = irBlocked(IR_LEFT), r = irBlocked(IR_RIGHT);
137  if (d < STOP_CM || (l && r)) avoid();
138  else if (l) { drive(TURN, -TURN); delay(150); }
139  else if (r) { drive(-TURN, TURN); delay(150); }
140  else if (d < SLOW_CM) { int s = map(d, STOP_CM, SLOW_CM, SLOW, CRUISE); drive(s, s); }
141  else drive(CRUISE, CRUISE);
142}

Robot penghindar rintangan dengan Raspberry Pi Pico (MicroPython)

Di Raspberry Pi Pico, fungsi time_pulse_us() di MicroPython bekerja seperti pulseIn() di Arduino; ia mengembalikan nilai negatif kalau tidak ada pantulan, jadi kita menganggapnya 400 cm, yaitu ruang kosong. Untuk servo kita memakai PWM 50 Hz dan duty_ns(), yang menerima lebar pulsa dalam nanodetik. Servo di GP16 dan pin kecepatan motor di GP15 dan GP10 berada di slice PWM yang berbeda, jadi frekuensinya tidak saling mengganggu. Kali ini kecepatan diberikan dalam persen. Pico tidak punya Bluetooth, jadi kalau kamu ingin mode manual, kamu bisa menghubungkan HC-05 ke UART0 (GP0, GP1) seperti di panduan mobil robot.

MicroPython
1from machine import Pin, PWM, time_pulse_us
2import time
3
4ena = PWM(Pin(15)); ena.freq(1000)          # sol motor hızı / left motor speed
5enb = PWM(Pin(10)); enb.freq(1000)          # sağ motor hızı / right motor speed
6in1, in2 = Pin(14, Pin.OUT), Pin(13, Pin.OUT)
7in3, in4 = Pin(12, Pin.OUT), Pin(11, Pin.OUT)
8servo = PWM(Pin(16)); servo.freq(50)        # servo sinyali, 50 Hz / servo signal, 50 Hz
9trig = Pin(17, Pin.OUT, value=0)
10echo = Pin(18, Pin.IN)                      # 1 kΩ / 2 kΩ bölücü üzerinden / via a 1 kΩ / 2 kΩ divider
11ir_left = Pin(19, Pin.IN, Pin.PULL_UP)      # 0 = engel / 0 = obstacle
12ir_right = Pin(20, Pin.IN, Pin.PULL_UP)
13
14STOP_CM, BACK_CM = 25, 12
15CRUISE, TURN = 75, 65                       # hız yüzdesi / speed in percent
16MS_PER_DEG = 4                              # kalibre et / calibrate
17SERVO_CENTER = 90                           # öne bakmıyorsa düzelt / adjust if not facing ahead
18
19def drive(left, right):                     # -100 … 100 (%)
20    in1.value(left > 0); in2.value(left < 0)
21    in3.value(right > 0); in4.value(right < 0)
22    ena.duty_u16(int(min(abs(left), 100) * 655))
23    enb.duty_u16(int(min(abs(right), 100) * 655))
24
25def head(offset):                           # + sol, - sağ / + left, - right
26    angle = max(0, min(180, SERVO_CENTER + offset))
27    servo.duty_ns((544 + angle * 1856 // 180) * 1000)   # 0,544–2,4 ms darbe / 0.544–2.4 ms pulse
28
29def ping_cm():
30    trig.value(1); time.sleep_us(10); trig.value(0)     # 10 µs tetik / 10 µs trigger
31    t = time_pulse_us(echo, 1, 25000)
32    return 400 if t < 0 else t // 58                    # negatif = yankı yok / negative = no echo
33
34def distance_cm():                          # 3 ölçümün ortancası / median of 3 readings
35    r = []
36    for _ in range(3):
37        r.append(ping_cm())
38        time.sleep_ms(60)
39    return sorted(r)[1]
40
41def turn_by(deg):                           # + sola, - sağa / + left, - right
42    if deg > 0:
43        drive(-TURN, TURN)
44    else:
45        drive(TURN, -TURN)
46    time.sleep_ms(int(abs(deg) * MS_PER_DEG))
47    drive(0, 0)
48    time.sleep_ms(100)
49
50def avoid():
51    drive(0, 0)
52    time.sleep_ms(120)
53    front = distance_cm()
54    sides = not ir_left.value() or not ir_right.value()
55    if front >= STOP_CM and not sides:
56        return                              # yanlış alarm / false alarm
57    if front < BACK_CM or sides:            # geri çekil / back off
58        drive(-TURN, -TURN); time.sleep_ms(350); drive(0, 0)
59    best_off, best_cm = 0, 0
60    for off in (70, 35, -35, -70):          # tara / scan
61        head(off)
62        time.sleep_ms(300)
63        cm = distance_cm()
64        if cm > best_cm:
65            best_off, best_cm = off, cm
66    head(0)
67    time.sleep_ms(200)
68    if best_cm < STOP_CM + 10:              # çıkmaz / dead end
69        drive(-TURN, -TURN); time.sleep_ms(400)
70        turn_by(180)
71    else:
72        turn_by(best_off)
73
74drive(0, 0)
75head(0)
76time.sleep(3)                               # yere koyman için süre / time to put it down
77while True:
78    d = ping_cm()
79    left_hit, right_hit = not ir_left.value(), not ir_right.value()
80    if d < STOP_CM or (left_hit and right_hit):
81        avoid()
82    elif left_hit:
83        drive(TURN, -TURN); time.sleep_ms(150)   # sağa kaç / dodge right
84    elif right_hit:
85        drive(-TURN, TURN); time.sleep_ms(150)   # sola kaç / dodge left
86    else:
87        drive(CRUISE, CRUISE)
88    time.sleep_ms(60)                        # ölçümler arası / between readings

Ide proyek dengan robot penghindar rintangan

  • Tampilan radar: Kirim sudut dan jarak dari pemindaian lewat port serial dan gambar layar radar hijau di komputermu; detailnya ada di artikel Proyek Radar Arduino.
  • Garis plus rintangan: Buat robot memutari kotak yang menghalangi jalannya sambil mengikuti lintasan seperti Robot Pengikut Garis, lalu kembali ke garis; ini tugas lomba yang umum.
  • Robot penyusur dinding: Biarkan sensor menoleh 60 derajat ke kanan dan jalankan robot dengan jarak tetap 20 cm dari dinding; ini langkah pertama untuk memecahkan labirin.
  • Robot dengan layar: Tampilkan jarak dan mode di layar OLED kecil; debugging jadi jauh lebih mudah.
  • Prototipe robot penyedot debu: Rancang robot pembersih yang berkeliling rumah dengan pilihan arah acak, sakelar tabrak, dan sensor jurang.
  • Tongkat pintar: Ubah logika pengukuran jarak yang sama menjadi peringatan getar untuk penyandang tunanetra; lihat Tongkat Pintar Arduino.
  • Proyek sekolah atau lomba: Presentasikan dengan lintasan rintangan, pengukuran waktu, dan demo mode otomatis dan manual; untuk ide, lihat artikel ide proyek Arduino untuk lomba sains.

Kesalahan umum dan cara memperbaikinya

MasalahKemungkinan penyebabSolusi
Robot menabrak dinding tanpa berhentiSensor membaca 0 (kabel putus, TRIG dan ECHO tertukar) dan kode menganggapnya ruang kosongJalankan sketch uji, coba 10–60 cm dengan tanganmu, cek pin TRIG dan ECHO
Robot menyerempet dinding ketika mendekat dengan sudut miringSuara terpantul dari permukaan miring ke arah lainTambahkan sensor IR di sudut depan dan turunkan kecepatan
Arduino reset ketika berhenti untuk memindaiArus servo dan motor membuat jalur 5 V anjlokKapasitor 470 µF di servo, sel 18650 yang terisi penuh; kalau perlu, beri daya servo dari sumber 5 V terpisah
Robot berhenti dan memindai tanpa alasanSatu pembacaan salah atau pantulan dari lantaiNaikkan sensor ke 8–12 cm dan miringkan sedikit ke atas; pakai konfirmasi median
Robot berbelok ke sisi yang terhalangServo terpasang terbalik, kiri dan kanan tertukarAtur SERVO_DIR ke -1
Beloknya terlalu pendek atau terlalu panjangMS_PER_DEG belum dikalibrasi atau baterai lemahUkur dengan turnBy(360) dan setel ulang dengan baterai penuh
Robot terus belok kiri-kanan di sudut ruanganKedua sisi mendekati ambang dan keputusannya terus bergantiNaikkan ambang jalan buntu (STOP_CM + 10) atau buat robot mengutamakan arah belok terakhir
Kepala sensor berkedutCatu servo lemah atau interrupt SoftwareSerialPerpendek kabel servo, tambahkan kapasitor, jangan mengirim perintah Bluetooth lebih sering dari yang perlu
Cara tercepat menemukan sumber masalah adalah membiarkan robot tetap di USB, menjalankannya dengan roda menggantung, dan mencetak nilai pingCm() ke Serial Monitor. Kalau nilainya masuk akal, masalahnya ada di sisi mekanik atau daya. Untuk penyebab lain Arduino terus restart, lihat artikel Arduino Terus Reset.

Karena menggabungkan pembacaan sensor, filter, pengambilan keputusan, dan kendali motor dalam satu proyek, robot penghindar rintangan adalah pintu masuk terbaik ke dunia robotika. Pertama, amati perilaku dasarnya dengan sketch pertama, lalu setel ambangnya sesuai ruanganmu dengan versi lanjutan, dan terakhir perkuat robotmu dengan sensor IR dan Bluetooth. Di aplikasi BlueGrays kamu akan menemukan proyek Robot Penghindar Rintangan, Mobil Kendali Bluetooth dengan L298N, Pengukuran Jarak HC-SR04, dan Sensor Parkir langkah demi langkah, lengkap dengan skema rangkaian dan kode.

Pertanyaan umum

Apa saja yang dibutuhkan untuk membuat robot penghindar rintangan?

Robot penghindar rintangan dasar butuh Arduino Uno, sensor ultrasonik HC-SR04, servo SG90, driver motor L298N atau L293D, kit sasis 2WD dengan dua motor DC bergearbox, dan dua sel 18650. Kamu bisa menambahkan dua sensor rintangan IR untuk melihat sudut dan modul Bluetooth HC-05 untuk mengemudikannya dari ponsel.

Bisakah membuat robot penghindar rintangan tanpa servo?

Bisa. Sensornya menghadap lurus ke depan; ketika robot melihat rintangan, ia berbelok dulu ke satu arah dan mengukur lagi, dan kalau jalannya masih terhalang, ia berbelok ke arah lain. Cara ini lebih murah, tapi robot memutuskan lebih lambat karena harus memutar seluruh badannya di setiap percobaan; servo memungkinkannya menemukan arah yang paling lega sebelum berbelok.

Kenapa HC-SR04 tidak melihat beberapa rintangan?

Sensor ultrasonik mengukur dengan pantulan. Permukaan lunak seperti gorden dan sofa menyerap suara, dinding miring memantulkannya ke arah lain, dan benda tipis seperti kaki kursi memberi pantulan yang sangat lemah. Sensor ini juga tidak bisa melihat rintangan di luar atau di bawah kerucutnya yang sekitar 15 derajat; celah ini bisa kamu tutup dengan sensor IR.

Di jarak berapa robot penghindar rintangan sebaiknya berhenti?

25 cm adalah nilai awal yang baik: jarak yang ditempuh di antara dua pembacaan, jarak pengereman, dan margin untuk berputar di tempat totalnya sekitar 20 cm, ditambah sedikit margin keamanan. Untuk robot yang lebih cepat dan lantai yang licin, naikkan ke 30–35 cm; dengan rintangan yang lebih dekat dari 12 cm, robot sebaiknya mundur dulu.

Mana yang lebih baik untuk robot, L298N atau shield L293D?

L298N bisa memberi 2 A per kanal, jadi lebih tangguh dan pinnya bebas kamu pilih. Shield L293D ditancapkan ke Uno, jadi mengurangi kabel dan bisa mengendalikan empat motor, tapi arus kontinunya 0,6 A per kanal dan memakai banyak pin. Untuk robot 2WD kecil dengan motor TT, keduanya sama-sama bisa.

Bisakah robot penghindar rintangan dikendalikan dari ponsel?

Bisa. Tambahkan modul Bluetooth HC-05 dan kirim huruf dari aplikasi remote di ponsel Android untuk beralih antara mode otomatis dan manual. Memakai sensor ultrasonik sebagai pelindung tabrakan di mode manual mencegahmu menabrakkan robot ke dinding. Dengan ESP32, kamu tidak perlu modul terpisah berkat Bluetooth bawaannya.

Lihat semua proyek
Pengukuran Jarak HC-SR04 (Tampilan Serial)
#27Pemula

Pengukuran Jarak HC-SR04 (Tampilan Serial)

Sensor HC-SR04 bekerja persis seperti kelelawar yang mencari jalan dalam gelap: ia mengirim suara yang tidak bisa kamu dengar, mendengarkan pantulannya, dan mengukur seberapa jauh benda di depannya. A

4.6(46)
71
Robot Penghindar Rintangan
#81Mahir
Premium

Robot Penghindar Rintangan

Bagaimana kalau membuat kendaraan pintar yang mencari jalannya sendiri? Robot Penghindar Rintangan terus memindai sekelilingnya berkat sensor ultrasonik di depannya. Ketika menemui rintangan, robot be

5.0(38)
49
Mobil Kendali Bluetooth dengan L298N
#80Mahir
Premium

Mobil Kendali Bluetooth dengan L298N

Jadikan ponselmu remote dan kendarai mobil robotmu sendiri. Arduino menerima perintah dari aplikasi remote control di ponselmu lewat modul Bluetooth dan memutar roda dengan driver motor; mobil maju, m

5.0(38)
65
Menggunakan Motor Servo
#35Pemula
Premium

Menggunakan Motor Servo

Lengan motor servo kecil berputar ke tiga posisi bergantian: penuh ke awal, tepat ke tengah, dan penuh ke akhir, menunggu dua detik di setiap perhentian. Arduino memberi tahu motor sudut mana yang har

4.7(48)
67
Sensor Parkir dengan HC-SR04
#28Menengah
Premium

Sensor Parkir dengan HC-SR04

Versi mini sensor parkir mobil: makin dekat sesuatu, makin cepat bunyi bipnya. Sensor jarak mengukur benda di depannya; jika jaraknya lebih dari 20 sentimeter LED hijau tetap menyala, dan begitu lebih

4.8(64)
85
Membaca Pantulan (Kedekatan) dengan TCRT5000
#77Menengah
Premium

Membaca Pantulan (Kedekatan) dengan TCRT5000

Dengan sensor kecil yang memancarkan cahaya tak terlihat dan mengukur berapa banyak yang terpantul kembali, kamu bisa mendeteksi permukaan di depannya. Makin dekat sebuah benda atau permukaan berwarna

4.6(33)
43
Deteksi Permukaan Hitam dan Putih TCRT5000
#78Menengah
Premium

Deteksi Permukaan Hitam dan Putih TCRT5000

Dengan sensor kecil yang menjadi mata robot pengikut garis, kamu bisa tahu apakah lantainya hitam atau putih. TCRT5000 menyinari lantai dengan cahaya tak terlihat dan mengecek berapa banyak yang terpa

4.7(40)
49
Sensor Jarak Ultrasonik HC-SR04 ESP32
#116Menengah

Sensor Jarak Ultrasonik HC-SR04 ESP32

Sensor ultrasonik HC-SR04 menghitung jarak dengan mengukur waktu yang dibutuhkan gelombang suara yang dipancarkannya untuk memantul dari benda lalu kembali (Time of Flight). Di proyek ini, kita mengirim pulsa 10 mikrodetik dari ESP32 ke pin TRIG sensor dan membaca durasi pantulan dari pin ECHO dengan pulseIn(). Jarak hasil hitung ditampilkan dalam sentimeter di LCD I2C 16x2. Karena HC-SR04 bekerja di 5V, pembagi tegangan wajib dipasang di pin ECHO.

4.9(28)
45