#include <Arduino.h>
#include "BluetoothSerial.h"
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth tidak diaktifkan! Pastikan board = ESP32.
#endif
BluetoothSerial SerialBT;
#define BT_NAME "RobotRC_ESP32"
unsigned long counter = 0;
bool lastConnected = false;
String bufferData = "";
unsigned long waktuTerakhirTerima = 0;
const unsigned long JEDA_GABUNG = 50; // ms
void setup() {
Serial.begin(115200);
SerialBT.begin(BT_NAME);
Serial.println();
Serial.println("============================================");
Serial.println(" MODE DETEKSI TOMBOL (HANYA TEKS)");
Serial.println("============================================");
Serial.print("Nama Bluetooth : "); Serial.println(BT_NAME);
Serial.println("Menunggu Android terhubung...");
Serial.println("============================================");
Serial.println();
}
void loop() {
// ===== Deteksi koneksi =====
bool connected = SerialBT.hasClient();
if (connected && !lastConnected) {
Serial.println(">>> ANDROID TERHUBUNG <<<");
Serial.println();
SerialBT.println("=== TERHUBUNG ===");
SerialBT.println("Tekan tombol di APK");
SerialBT.println("=================");
} else if (!connected && lastConnected) {
Serial.println("<<< ANDROID TERPUTUS >>>");
Serial.println();
}
lastConnected = connected;
// ===== Kumpulkan data masuk =====
while (SerialBT.available()) {
bufferData += (char)SerialBT.read();
waktuTerakhirTerima = millis();
}
// ===== Proses paket setelah jeda =====
if (bufferData.length() > 0 && (millis() - waktuTerakhirTerima > JEDA_GABUNG)) {
prosesPaket(bufferData);
bufferData = "";
}
delay(5);
}
// ===== Proses dan tampilkan paket =====
void prosesPaket(String data) {
counter++;
// Bentuk teks yang mudah dibaca (escape karakter khusus)
String teksTampil = "";
for (unsigned int i = 0; i < data.length(); i++) {
char c = data[i];
if (c == '\r') teksTampil += "\\r";
else if (c == '\n') teksTampil += "\\n";
else if (c == '\t') teksTampil += "\\t";
else if (c < 32) teksTampil += "?";
else teksTampil += c;
}
// ===== Serial Monitor =====
Serial.print("#");
Serial.print(counter);
Serial.print(" | ");
Serial.print(data.length());
Serial.print("B | \"");
Serial.print(teksTampil);
Serial.println("\"");
// ===== Kirim balik ke Android =====
SerialBT.print("#");
SerialBT.print(counter);
SerialBT.print(" | \"");
SerialBT.print(teksTampil);
SerialBT.println("\"");
}
#include <BluetoothSerial.h>
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth tidak aktif! Pastikan Board = ESP32
#endif
BluetoothSerial SerialBT;
// ===== Pin Motor Driver L298N (tanpa ENA/ENB) =====
#define IN1 26
#define IN2 27
#define IN3 14
#define IN4 12
// ===== Nama Bluetooth =====
#define BT_NAME "RobotRC_ESP32"
// Buffer untuk baca perintah (bisa multi-byte)
String commandBuffer = "";
void setup() {
Serial.begin(115200);
// Setup pin motor
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
// Motor berhenti di awal
stopMotor();
// Mulai Bluetooth
SerialBT.begin(BT_NAME);
Serial.println();
Serial.println("==========================================");
Serial.println(" ROBOT RC ESP32 - DEBUG MODE");
Serial.println("==========================================");
Serial.print("Bluetooth Name : ");
Serial.println(BT_NAME);
Serial.println("Menunggu koneksi dari Android...");
Serial.println("==========================================");
Serial.println("Format log:");
Serial.println(" [RAW] -> karakter mentah yang diterima");
Serial.println(" [HEX] -> kode hex karakter");
Serial.println(" [DEC] -> kode desimal");
Serial.println(" [AKSI] -> aksi yang dijalankan");
Serial.println("==========================================");
Serial.println();
}
void loop() {
// ===== Cek koneksi Bluetooth =====
static bool lastConnected = false;
bool connected = SerialBT.hasClient();
if (connected && !lastConnected) {
Serial.println(">>> [BT] ANDROID TERHUBUNG <<<");
} else if (!connected && lastConnected) {
Serial.println("<<< [BT] ANDROID TERPUTUS >>>");
}
lastConnected = connected;
// ===== Baca data Bluetooth =====
while (SerialBT.available()) {
char c = SerialBT.read();
// Tampilkan info lengkap tiap karakter
printCharInfo(c);
// Proses sebagai perintah
processCommand(c);
}
delay(10);
}
// ===== Fungsi Debug: tampilkan detail karakter =====
void printCharInfo(char c) {
Serial.print("[RAW] '");
if (c == '\n') Serial.print("\\n");
else if (c == '\r') Serial.print("\\r");
else if (c == '\t') Serial.print("\\t");
else if (c < 32) Serial.print("?");
else Serial.print(c);
Serial.print("'");
Serial.print(" | [HEX] 0x");
if (c < 16) Serial.print("0");
Serial.print((uint8_t)c, HEX);
Serial.print(" | [DEC] ");
Serial.print((int)(uint8_t)c);
Serial.println();
}
// ===== Fungsi proses perintah utama =====
void processCommand(char c) {
String aksi = "";
switch (c) {
case 'F': case 'f': maju(); aksi = "MAJU"; break;
case 'B': case 'b': mundur(); aksi = "MUNDUR"; break;
case 'L': case 'l': kiri(); aksi = "KIRI"; break;
case 'R': case 'r': kanan(); aksi = "KANAN"; break;
case 'S': case 's': stopMotor(); aksi = "STOP"; break;
case 'G': case 'g': majuKiri(); aksi = "MAJU-KIRI"; break;
case 'I': case 'i': majuKanan(); aksi = "MAJU-KANAN"; break;
case 'H': case 'h': mundurKiri(); aksi = "MUNDUR-KIRI"; break;
case 'J': case 'j': mundurKanan();aksi = "MUNDUR-KANAN";break;
default:
Serial.println(" >> [AKSI] (tidak dikenali / diabaikan)");
Serial.println();
return;
}
Serial.print(" >> [AKSI] ");
Serial.println(aksi);
Serial.println();
}
// ===== Fungsi gerakan motor =====
void maju() {
digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW);
digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW);
}
void mundur() {
digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH);
digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH);
}
void kiri() {
// Belok kiri di tempat
digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH);
digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW);
}
void kanan() {
// Belok kanan di tempat
digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH);
}
void majuKiri() {
digitalWrite(IN1, LOW); digitalWrite(IN2, LOW);
digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW);
}
void majuKanan() {
digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW); digitalWrite(IN4, LOW);
}
void mundurKiri() {
digitalWrite(IN1, LOW); digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH);
}
void mundurKanan() {
digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH);
digitalWrite(IN3, LOW); digitalWrite(IN4, LOW);
}
void stopMotor() {
digitalWrite(IN1, LOW); digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW); digitalWrite(IN4, LOW);
}
#include <Arduino.h>
#include "BluetoothSerial.h"
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth tidak diaktifkan! Pastikan board = ESP32.
#endif
BluetoothSerial SerialBT;
// ============================================================
// KONFIGURASI PIN (semua nomor GPIO ESP32)
// ============================================================
// ----- Motor Driver L298N -----
#define PIN_IN1 26 // GPIO 26 → IN1 (motor kiri, arah 1)
#define PIN_IN2 27 // GPIO 27 → IN2 (motor kiri, arah 2)
#define PIN_IN3 14 // GPIO 14 → IN3 (motor kanan, arah 1)
#define PIN_IN4 12 // GPIO 12 → IN4 (motor kanan, arah 2)
#define PIN_ENA 25 // GPIO 25 → ENA (PWM kecepatan motor kiri)
#define PIN_ENB 13 // GPIO 13 → ENB (PWM kecepatan motor kanan)
// ----- Sensor Ultrasonik HC-SR04 -----
#define PIN_TRIG 5 // GPIO 5 → TRIG
#define PIN_ECHO 18 // GPIO 18 → ECHO (wajib voltage divider!)
// ----- Rudal -----
#define PIN_RUDAL 4 // GPIO 4 → sinyal ke transistor rudal
// ----- Buzzer -----
#define PIN_BUZZER 2 // GPIO 2 → buzzer (active buzzer)
// ----- LED Indikator Bluetooth -----
#define PIN_LED 15 // GPIO 15 → LED indikator koneksi
// ============================================================
// KONFIGURASI PWM (ESP32 core 3.x)
// ============================================================
#define PWM_FREQ 1000
#define PWM_RES 8
// ============================================================
// LEVEL KECEPATAN (0-255)
// ============================================================
#define SPD_1 100 // W = lamban
#define SPD_2 160 // X = agak kencang
#define SPD_3 220 // Y = kencang
#define SPD_4 255 // Z = kencang sekali
// ============================================================
// KONFIGURASI AUTOPILOT
// ============================================================
#define JARAK_BERHENTI 15
#define JARAK_AMAN 25
#define DURASI_RUDAL 500
// ============================================================
// KONFIGURASI BUZZER (bip-bip)
// ============================================================
#define BUZZER_ON_MS 150
#define BUZZER_OFF_MS 150
// ============================================================
// KONFIGURASI LED INDIKATOR
// ============================================================
#define LED_KEDIP_MS 500 // interval kedip saat belum terhubung
// ============================================================
// NAMA BLUETOOTH
// ============================================================
#define BT_NAME "RobotRC_ESP32"
// ============================================================
// VARIABEL GLOBAL
// ============================================================
int kecepatanKiri = SPD_2;
int kecepatanKanan = SPD_2;
bool modeAuto = false;
bool rudalAktif = false;
unsigned long rudalMulai = 0;
char lastCmd = 0;
unsigned long lastCmdTime = 0;
const unsigned long JEDA_MIN = 50;
int autoState = 0;
// ----- Buzzer -----
bool buzzerAktif = false;
bool buzzerNyala = false;
unsigned long buzzerTimer = 0;
// ----- LED Indikator -----
bool ledNyala = false;
unsigned long ledTimer = 0;
// ============================================================
// SETUP
// ============================================================
void setup() {
Serial.begin(115200);
// ----- Motor -----
pinMode(PIN_IN1, OUTPUT);
pinMode(PIN_IN2, OUTPUT);
pinMode(PIN_IN3, OUTPUT);
pinMode(PIN_IN4, OUTPUT);
// ----- PWM ESP32 core 3.x -----
ledcAttach(PIN_ENA, PWM_FREQ, PWM_RES);
ledcAttach(PIN_ENB, PWM_FREQ, PWM_RES);
ledcWrite(PIN_ENA, 0);
ledcWrite(PIN_ENB, 0);
// ----- HC-SR04 -----
pinMode(PIN_TRIG, OUTPUT);
pinMode(PIN_ECHO, INPUT);
digitalWrite(PIN_TRIG, LOW);
// ----- Rudal -----
pinMode(PIN_RUDAL, OUTPUT);
digitalWrite(PIN_RUDAL, LOW);
// ----- Buzzer -----
pinMode(PIN_BUZZER, OUTPUT);
digitalWrite(PIN_BUZZER, LOW);
// ----- LED Indikator -----
pinMode(PIN_LED, OUTPUT);
digitalWrite(PIN_LED, LOW);
stopMotor();
// ----- Bluetooth -----
SerialBT.begin(BT_NAME);
Serial.println();
Serial.println("============================================");
Serial.println(" ROBOT RC ESP32 - MANUAL + AUTOPILOT");
Serial.println("============================================");
Serial.print ("Bluetooth : "); Serial.println(BT_NAME);
Serial.println("--------------------------------------------");
Serial.println("PIN YANG DIPAKAI:");
Serial.println(" IN1=26 IN2=27 IN3=14 IN4=12");
Serial.println(" ENA=25 ENB=13");
Serial.println(" TRIG=5 ECHO=18");
Serial.println(" RUDAL=4 BUZZER=2 LED=15");
Serial.println("--------------------------------------------");
Serial.println("PERINTAH:");
Serial.println(" F/B/L/R : maju / mundur / kiri / kanan");
Serial.println(" M/N : putar kiri / putar kanan");
Serial.println(" S : stop");
Serial.println(" W/X/Y/Z : speed 1 / 2 / 3 / 4");
Serial.println(" A : tembak rudal");
Serial.println(" P : buzzer bip-bip (toggle)");
Serial.println(" q : mode MANUAL");
Serial.println(" Q : mode AUTOPILOT");
Serial.println("============================================");
Serial.println();
}
// ============================================================
// LOOP
// ============================================================
void loop() {
static bool lastConnected = false;
bool connected = SerialBT.hasClient();
if (connected && !lastConnected) {
Serial.println(">>> ANDROID TERHUBUNG <<<");
SerialBT.println("=== ROBOT SIAP ===");
SerialBT.println("Mode : MANUAL");
SerialBT.println("Speed: 2");
digitalWrite(PIN_LED, HIGH); // LED nyala statis
ledNyala = true;
} else if (!connected && lastConnected) {
Serial.println("<<< ANDROID TERPUTUS >>>");
stopMotor();
digitalWrite(PIN_RUDAL, LOW);
rudalAktif = false;
buzzerAktif = false;
digitalWrite(PIN_BUZZER, LOW);
}
lastConnected = connected;
// ----- Baca perintah Bluetooth -----
if (SerialBT.available()) {
char c = SerialBT.read();
unsigned long now = millis();
if (!(c == lastCmd && (now - lastCmdTime) < JEDA_MIN)) {
lastCmd = c;
lastCmdTime = now;
prosesPerintah(c);
}
}
// ----- Auto-off rudal -----
if (rudalAktif && (millis() - rudalMulai >= DURASI_RUDAL)) {
digitalWrite(PIN_RUDAL, LOW);
rudalAktif = false;
Serial.println("[RUDAL] selesai");
SerialBT.println("[RUDAL] selesai");
}
// ----- Buzzer bip-bip -----
handleBuzzer();
// ----- LED indikator -----
handleLED(connected);
// ----- Autopilot -----
if (modeAuto) jalankanAutopilot();
delay(5);
}
// ============================================================
// LED INDIKATOR KONEKSI
// - Belum terhubung : kedip 500ms ON / 500ms OFF
// - Terhubung : nyala statis (HIGH)
// ============================================================
void handleLED(bool connected) {
if (connected) {
// sudah di-handle di loop saat transisi, tapi pastikan tetap HIGH
if (!ledNyala) {
digitalWrite(PIN_LED, HIGH);
ledNyala = true;
}
return;
}
// Belum terhubung → kedip
unsigned long now = millis();
if (now - ledTimer >= LED_KEDIP_MS) {
ledNyala = !ledNyala;
digitalWrite(PIN_LED, ledNyala ? HIGH : LOW);
ledTimer = now;
}
}
// ============================================================
// PROSES PERINTAH
// ============================================================
void prosesPerintah(char c) {
String info = "";
switch (c) {
case 'F': case 'f':
if (!modeAuto) { maju(); info = "MAJU"; }
else info = "IGNORED (AUTO)";
break;
case 'B': case 'b':
if (!modeAuto) { mundur(); info = "MUNDUR"; }
else info = "IGNORED (AUTO)";
break;
case 'L': case 'l':
if (!modeAuto) { kiri(); info = "KIRI"; }
else info = "IGNORED (AUTO)";
break;
case 'R': case 'r':
if (!modeAuto) { kanan(); info = "KANAN"; }
else info = "IGNORED (AUTO)";
break;
case 'M': case 'm':
if (!modeAuto) { putarKiri(); info = "PUTAR KIRI"; }
else info = "IGNORED (AUTO)";
break;
case 'N': case 'n':
if (!modeAuto) { putarKanan(); info = "PUTAR KANAN"; }
else info = "IGNORED (AUTO)";
break;
case 'S': case 's':
if (!modeAuto) { stopMotor(); info = "STOP"; }
else info = "IGNORED (AUTO)";
break;
case 'W': case 'w':
kecepatanKiri = kecepatanKanan = SPD_1;
info = "SPEED 1 (lamban)";
if (!modeAuto) updatePWM();
break;
case 'X': case 'x':
kecepatanKiri = kecepatanKanan = SPD_2;
info = "SPEED 2 (agak kencang)";
if (!modeAuto) updatePWM();
break;
case 'Y': case 'y':
kecepatanKiri = kecepatanKanan = SPD_3;
info = "SPEED 3 (kencang)";
if (!modeAuto) updatePWM();
break;
case 'Z': case 'z':
kecepatanKiri = kecepatanKanan = SPD_4;
info = "SPEED 4 (kencang sekali)";
if (!modeAuto) updatePWM();
break;
case 'A': case 'a':
tembakRudal();
info = "RUDAL DITEMBAK!";
break;
case 'P': case 'p':
buzzerAktif = !buzzerAktif;
if (!buzzerAktif) {
digitalWrite(PIN_BUZZER, LOW);
buzzerNyala = false;
info = "BUZZER OFF";
} else {
buzzerTimer = millis();
buzzerNyala = false;
digitalWrite(PIN_BUZZER, LOW);
info = "BUZZER ON (bip-bip)";
}
break;
case 'q':
modeAuto = false;
stopMotor();
info = "MODE MANUAL";
break;
case 'Q':
modeAuto = true;
stopMotor();
autoState = 0;
info = "MODE AUTOPILOT";
break;
default:
return;
}
Serial.print("[CMD] '");
Serial.print(c);
Serial.print("' -> ");
Serial.println(info);
SerialBT.print("[");
SerialBT.print(info);
SerialBT.println("]");
}
// ============================================================
// KONTROL MOTOR
// ============================================================
void maju() {
digitalWrite(PIN_IN1, HIGH); digitalWrite(PIN_IN2, LOW);
digitalWrite(PIN_IN3, HIGH); digitalWrite(PIN_IN4, LOW);
updatePWM();
}
void mundur() {
digitalWrite(PIN_IN1, LOW); digitalWrite(PIN_IN2, HIGH);
digitalWrite(PIN_IN3, LOW); digitalWrite(PIN_IN4, HIGH);
updatePWM();
}
void kiri() {
digitalWrite(PIN_IN1, LOW); digitalWrite(PIN_IN2, HIGH);
digitalWrite(PIN_IN3, HIGH); digitalWrite(PIN_IN4, LOW);
updatePWM();
}
void kanan() {
digitalWrite(PIN_IN1, HIGH); digitalWrite(PIN_IN2, LOW);
digitalWrite(PIN_IN3, LOW); digitalWrite(PIN_IN4, HIGH);
updatePWM();
}
void putarKiri() {
digitalWrite(PIN_IN1, LOW); digitalWrite(PIN_IN2, HIGH);
digitalWrite(PIN_IN3, HIGH); digitalWrite(PIN_IN4, LOW);
updatePWM();
}
void putarKanan() {
digitalWrite(PIN_IN1, HIGH); digitalWrite(PIN_IN2, LOW);
digitalWrite(PIN_IN3, LOW); digitalWrite(PIN_IN4, HIGH);
updatePWM();
}
void stopMotor() {
digitalWrite(PIN_IN1, LOW); digitalWrite(PIN_IN2, LOW);
digitalWrite(PIN_IN3, LOW); digitalWrite(PIN_IN4, LOW);
ledcWrite(PIN_ENA, 0);
ledcWrite(PIN_ENB, 0);
}
void updatePWM() {
ledcWrite(PIN_ENA, kecepatanKiri);
ledcWrite(PIN_ENB, kecepatanKanan);
}
// ============================================================
// RUDAL
// ============================================================
void tembakRudal() {
digitalWrite(PIN_RUDAL, HIGH);
rudalAktif = true;
rudalMulai = millis();
Serial.println("[RUDAL] AKTIF");
}
// ============================================================
// BUZZER BIP-BIP
// ============================================================
void handleBuzzer() {
if (!buzzerAktif) return;
unsigned long now = millis();
if (!buzzerNyala && (now - buzzerTimer >= BUZZER_OFF_MS)) {
digitalWrite(PIN_BUZZER, HIGH);
buzzerNyala = true;
buzzerTimer = now;
} else if (buzzerNyala && (now - buzzerTimer >= BUZZER_ON_MS)) {
digitalWrite(PIN_BUZZER, LOW);
buzzerNyala = false;
buzzerTimer = now;
}
}
// ============================================================
// ULTRASONIK
// ============================================================
long bacaJarak() {
digitalWrite(PIN_TRIG, LOW);
delayMicroseconds(2);
digitalWrite(PIN_TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(PIN_TRIG, LOW);
long durasi = pulseIn(PIN_ECHO, HIGH, 30000);
if (durasi == 0) return -1;
return durasi * 0.034 / 2;
}
// ============================================================
// AUTOPILOT
// ============================================================
void jalankanAutopilot() {
long jarak = bacaJarak();
if (jarak < 0) { stopMotor(); return; }
switch (autoState) {
case 0:
if (jarak > JARAK_AMAN) {
maju();
autoState = 1;
Serial.print("[AUTO] "); Serial.print(jarak);
Serial.println(" cm -> MAJU");
} else if (jarak <= JARAK_BERHENTI) {
stopMotor(); delay(200);
mundur(); delay(500);
stopMotor();
autoState = 2;
Serial.print("[AUTO] "); Serial.print(jarak);
Serial.println(" cm -> MUNDUR");
} else {
autoState = 3;
Serial.print("[AUTO] "); Serial.print(jarak);
Serial.println(" cm -> CARI ARAH");
}
break;
case 1:
if (jarak <= JARAK_BERHENTI) {
stopMotor();
autoState = 0;
Serial.println("[AUTO] Halangan -> berhenti");
} else {
maju();
}
break;
case 2:
stopMotor();
autoState = 3;
break;
case 3:
putarKiri(); delay(400); stopMotor();
{
long j2 = bacaJarak();
if (j2 > JARAK_AMAN) { autoState = 1; Serial.println("[AUTO] Kiri aman"); }
else { autoState = 4; Serial.println("[AUTO] Coba kanan"); }
}
break;
case 4:
putarKanan(); delay(400); stopMotor();
{
long j2 = bacaJarak();
if (j2 > JARAK_AMAN) { autoState = 1; Serial.println("[AUTO] Kanan aman"); }
else { autoState = 2; Serial.println("[AUTO] Mundur lagi"); }
}
break;
}
}