Membuat gerakan ombak
GERAKAN OMBAK (WAVE MOTION) BEAM MINIATUR RAKITAN BY AKBAR MINI SOUND SYSTEM
Di halaman ini, Sound Akbar Audio 95 bongkar tuntas kode Arduino yang saya gunakan di video terbaru untuk menghasilkan Gerakan Ombak (Wave Motion) yang super halus dan berganti mode otomatis pada 8 unit servo beam miniatur.
Kode ini sangat efisien karena menggunakan prinsip Non-Blocking dan State Machine.
A. Bedah Kode Terperinci: Logika Gerakan Ombak
Sahabat Miniatur, mari kita telaah bagian-bagian penting dari kode ini agar Anda bisa memodifikasinya sendiri:
1. Inisiasi & Kontrol Kecepatan (Kunci Gerakan Halus)
Bagian ini mendefinisikan koneksi pin dan kecepatan gerakan. Nilai servoStepDelay adalah kunci:
* int assignedServoPins[8]: Tentukan pin digital Arduino yang terhubung ke 8 servo Anda.
* int servoStepDelay = 25;: Ini adalah kecepatan mikro (waktu tunggu dalam milidetik per 1 derajat gerakan). Semakin kecil nilai ini, semakin cepat dan halus gerakan servo dari Sudut A ke Sudut B, tanpa terlihat tersentak.
* unsigned long lastServoStepTime = 0;: Timer yang bekerja dengan fungsi millis() untuk menjalankan gerakan step-by-step (Non-Blocking).
2. Logika Utama: Penentuan Sudut Tujuan (handleModeOmbak())
Fungsi ini adalah otak yang mengatur kapan dan kemana servo harus bergerak (targetAngle). Logika di dalamnya:
* Sub-Mode 1: Saling Susul Berantai (Gelombang Datang)
* Menggunakan switch (currentStep): Ini adalah State Machine yang memastikan servo S5 hingga S8 bergerak naik dan turun satu per satu dengan jeda tertentu, menciptakan efek gelombang yang berurutan.
* Sub-Mode 2: Berlawanan Terus-Menerus (Gelombang Bertemu)
* Servo Luar (S5, S8) dan Servo Dalam (S6, S7) bergerak berlawanan arah secara serempak (Luar Naik/Dalam Turun, lalu sebaliknya).
* Menggunakan MODE6_STAGGER_DELAY = 650; sebagai jeda waktu tunggu antar perpindahan mode di Sub-Mode ini.
* Transisi Otomatis: Kedua sub-mode ini otomatis berganti setelah 7 kali siklus penuh.
3. Kunci Non-Blocking (Fungsi loop())
Fungsi loop() memastikan kode tidak "macet" atau blocking saat servo bergerak, sehingga Arduino tetap responsif untuk fungsi lain (jika ada).
* handleModeOmbak(): Dipanggil setiap saat untuk update sudut tujuan baru (Target).
* if (currentMillis - lastServoStepTime >= servoStepDelay): Ini adalah pengecek waktu 25ms utama. Gerakan servo (penambahan atau pengurangan 1 derajat) hanya dijalankan di dalam blok ini. Ini yang membuat gerakan halus, karena servo mencapai target sedikit demi sedikit.
C. KODE LENGKAP UTUH (Siap Salin)
Sahabat Miniatur, salin seluruh blok kode di bawah ini, paste di Arduino IDE Anda, dan langsung unggah ke mikrokontroler Anda!
=======================
#include <Servo.h>
// --- KONSTANTA PIN DAN MODE ---
// Anggap servo terpasang pada pin 3 sampai 10
// Silakan sesuaikan jika pin servo Anda berbeda
int assignedServoPins[8] = {3, 4, 5, 6, 7, 8, 9, 10};
// --- OBJEK SERVO ---
Servo servo[8];
// --- VARIABEL KONTROL GERAKAN ---
int currentActiveMode = 6;
int servoStepDelay = 25; // Kecepatan pergerakan servo (25ms per langkah)
int targetAngle[8]; // Sudut tujuan setiap servo
int currentAngle[8]; // Sudut saat ini setiap servo
unsigned long lastServoStepTime = 0; // Timer untuk pergerakan bertahap
// --- VARIABEL KHUSUS MODE OMBAK ---
int mode6SubMode = 1; // Mulai dengan Sub-Mode 1 (Saling Susul)
int currentStep = 0; // Langkah (state) saat ini dalam sub-mode
unsigned long lastServoSequenceTrigger = 0; // Timer untuk jeda antara langkah
const int MODE6_STAGGER_DELAY = 650; // Jeda waktu statis untuk Sub-Mode 2 (Ombak Berlawanan)
// --- FUNGSI HELPER: Cek Apakah Semua Servo Sudah Mencapai Target ---
bool checkAllServosReachedTarget() {
for (int i = 0; i < 8; i++) {
if (currentAngle[i] != targetAngle[i]) {
return false;
}
}
return true;
}
// ------------------------------------------------------------------
// *** FUNGSI UTAMA: LOGIKA MODE OMBAK ***
// ------------------------------------------------------------------
void handleModeOmbak() {
unsigned long currentMillis = millis();
bool allServosReachedTarget = checkAllServosReachedTarget();
// ====================================
// SUB-MODE 1: SALING SUSUL BERANTAI (Seperti Gelombang Datang)
// Servo bergerak berurutan 5 -> 6 -> 7 -> 8, lalu turun berurutan
// ================================
if (mode6SubMode == 1) {
// Langkah 0: Inisiasi Awal
if (currentStep == 0) {
// S1-S4 (Index 0-3) diatur ke Netral (50°)
for (int i = 0; i < 4; i++) targetAngle[i] = 50;
// S5-S8 (Index 4-7) diatur ke Bawah (20°)
targetAngle[4] = 20; targetAngle[5] = 20; targetAngle[6] = 20; targetAngle[7] = 20;
lastServoSequenceTrigger = currentMillis;
currentStep = 1; // Pindah ke langkah pertama gerakan
}
// Jeda waktu antara setiap langkah (S5 naik, jeda, S6 naik, dst.)
// Kecepatan mikro servoStepDelay dikalikan 30 (sesuai setting sebelumnya)
unsigned long waveStaggerDelay = servoStepDelay * 30;
if (currentMillis - lastServoSequenceTrigger >= waveStaggerDelay) {
lastServoSequenceTrigger = currentMillis;
// STATE MACHINE: Menggerakkan servo satu per satu
switch (currentStep) {
case 1: targetAngle[4] = 90; currentStep = 2; break; // S5 NAIK (Atas)
case 2: targetAngle[5] = 90; currentStep = 3; break; // S6 NAIK
case 3: targetAngle[6] = 90; currentStep = 4; break; // S7 NAIK
case 4: targetAngle[7] = 90; currentStep = 5; break; // S8 NAIK
case 5: targetAngle[4] = 20; currentStep = 6; break; // S5 TURUN (Bawah)
case 6: targetAngle[5] = 20; currentStep = 7; break; // S6 TURUN
case 7: targetAngle[6] = 20; currentStep = 8; break; // S7 TURUN
case 8:
targetAngle[7] = 20; // S8 TURUN
currentStep = 1; // Kembali ke langkah 1 (looping)
// Logika Transisi: Pindah ke Sub-Mode 2 setelah 7 siklus
static int subMode1CycleCounter = 0;
subMode1CycleCounter++;
if (subMode1CycleCounter >= 7) {
mode6SubMode = 2;
currentStep = 0;
subMode1CycleCounter = 0;
Serial.println("Ombak Sub-Mode Switch: 2 (Berlawanan)");
}
break;
}
}
// =======================================================
// SUB-MODE 2: BERLAWANAN TERUS-MENERUS (Ombak Dua Arah)
// Servo luar (S5, S8) dan Servo dalam (S6, S7) bergantian
// =======================================================
} else if (mode6SubMode == 2) {
// Langkah 0: Inisiasi Awal
if (currentStep == 0) {
for (int i = 0; i < 4; i++) targetAngle[i] = 50;
// Posisi Awal: Luar (S5, S8) Bawah, Dalam (S6, S7) Atas
targetAngle[4] = 20; targetAngle[7] = 20;
targetAngle[5] = 90; targetAngle[6] = 90;
currentStep = 1;
lastServoSequenceTrigger = currentMillis;
}
// Tunggu sampai semua servo mencapai target DAN jeda telah dilewati
if (allServosReachedTarget && currentMillis - lastServoSequenceTrigger >= MODE6_STAGGER_DELAY) {
lastServoSequenceTrigger = currentMillis;
// Logika Bergantian: Jika S5 (Luar) sedang di Atas, pindahkan ke Bawah, dan sebaliknya
if (targetAngle[4] == 90) {
// Aksi: Luar turun, Dalam naik
targetAngle[4] = 20; targetAngle[7] = 20;
targetAngle[5] = 90; targetAngle[6] = 90;
Serial.println("Ombak 2: Luar Bawah, Dalam Atas");
} else {
// Aksi: Luar naik, Dalam turun
targetAngle[4] = 90; targetAngle[7] = 90;
targetAngle[5] = 20; targetAngle[6] = 20;
Serial.println("Ombak 2: Luar Atas, Dalam Bawah");
}
// Logika Transisi: Kembali ke Sub-Mode 1 setelah 7 siklus
static int subMode2CycleCounter = 0;
subMode2CycleCounter++;
if (subMode2CycleCounter >= 7) {
mode6SubMode = 1;
currentStep = 0; // Kembali ke inisiasi Sub-Mode 1
subMode2CycleCounter = 0;
Serial.println("Ombak Sub-Mode Switch: 1 (Saling Susul)");
}
}
}
}
// ------------------------------------------------------------------
// *** SETUP DAN LOOP STANDALONE ***
// ------------------------------------------------------------------
void setup() {
Serial.begin(9600);
Serial.println("--- STANDALONE WAVE MOTION STARTING ---");
// Inisiasi Servo
for (int i = 0; i < 8; i++) {
servo[i].attach(assignedServoPins[i]);
currentAngle[i] = 50;
targetAngle[i] = 50; // Awalnya semua netral
servo[i].write(currentAngle[i]);
}
Serial.println("Servos Initialized to 50 degrees.");
// Panggil logika mode Ombak pertama kali untuk inisiasi target
handleModeOmbak();
}
void loop() {
unsigned long currentMillis = millis();
// 1. Jalankan Logika Mode Ombak (Menentukan target angle)
handleModeOmbak();
// 2. LOGIKA PERGERAKAN SERVO (NON-BLOCKING)
// Menggerakkan servo 1 derajat setiap servoStepDelay (25ms)
if (currentMillis - lastServoStepTime >= servoStepDelay) {
lastServoStepTime = currentMillis;
for (int i = 0; i < 8; i++) {
if (currentAngle[i] != targetAngle[i]) {
// Tentukan arah gerakan (maju atau mundur 1 derajat)
int moveDir = (targetAngle[i] > currentAngle[i]) ? 1 : -1;
currentAngle[i] += moveDir;
servo[i].write(currentAngle[i]);
}
}
}
}
//akhir code untuk anda salin
Dan kami tambahkan lagi code versi bahasa Indonesia nya
Agar sahabat miniatur dapat mempermudah memahami konsep pada code tersebut
#include <Servo.h>
// --- KONSTANTA PIN DAN MODE ---
// Pin Servo terpasang pada pin 3 sampai 10.
// Silakan sesuaikan jika pin servo Anda berbeda
int PinServoTerpasang[8] = {3, 4, 5, 6, 7, 8, 9, 10};
// --- OBJEK SERVO ---
Servo unitServo[8];
// --- VARIABEL KONTROL GERAKAN ---
int ModeAktifSaatIni = 6;
int JedaLangkahServo = 25; // Kecepatan pergerakan servo (25ms per langkah)
int SudutTujuan[8]; // Sudut tujuan setiap servo
int SudutSaatIni[8]; // Sudut saat ini setiap servo
unsigned long WaktuLangkahServoTerakhir = 0; // Timer untuk pergerakan bertahap (Non-Blocking)
// --- VARIABEL KHUSUS MODE OMBAK ---
int SubModeOmbak = 1; // Mulai dengan Sub-Mode 1 (Saling Susul)
int LangkahSaatIni = 0; // Langkah (state) saat ini dalam sub-mode
unsigned long PemicuUrutanServoTerakhir = 0; // Timer untuk jeda antara langkah (antara S5 naik, S6 naik, dst.)
const int JEDA_STATIS_OMBAK = 650; // Jeda waktu statis untuk Sub-Mode 2 (Ombak Berlawanan)
// --- FUNGSI HELPER: Cek Apakah Semua Servo Sudah Mencapai Target ---
bool cekSemuaServoCapaiTujuan() {
for (int i = 0; i < 8; i++) {
if (SudutSaatIni[i] != SudutTujuan[i]) {
return false;
}
}
return true;
}
// ------------------------------------------------------------------
// *** FUNGSI UTAMA: LOGIKA MODE OMBAK ***
// ------------------------------------------------------------------
void aturModeOmbak() { // Fungsi: handleModeOmbak()
unsigned long waktuSekarang = millis();
bool semuaServoCapaiTujuan = cekSemuaServoCapaiTujuan();
// =======================================================
// SUB-MODE 1: SALING SUSUL BERANTAI (Seperti Gelombang Datang)
// Servo bergerak berurutan 5 -> 6 -> 7 -> 8, lalu turun berurutan
// =======================================================
if (SubModeOmbak == 1) {
// Langkah 0: Inisiasi Awal
if (LangkahSaatIni == 0) {
// S1-S4 (Index 0-3) diatur ke Netral (50°)
for (int i = 0; i < 4; i++) SudutTujuan[i] = 50;
// S5-S8 (Index 4-7) diatur ke Bawah (20°)
SudutTujuan[4] = 20; SudutTujuan[5] = 20; SudutTujuan[6] = 20; SudutTujuan[7] = 20;
PemicuUrutanServoTerakhir = waktuSekarang;
LangkahSaatIni = 1; // Pindah ke langkah pertama gerakan
}
// Jeda waktu antara setiap langkah (S5 naik, jeda, S6 naik, dst.)
unsigned long JedaUrutanOmbak = JedaLangkahServo * 30;
if (waktuSekarang - PemicuUrutanServoTerakhir >= JedaUrutanOmbak) {
PemicuUrutanServoTerakhir = waktuSekarang;
// STATE MACHINE: Menggerakkan servo satu per satu
switch (LangkahSaatIni) {
case 1: SudutTujuan[4] = 90; LangkahSaatIni = 2; break; // S5 NAIK (Atas)
case 2: SudutTujuan[5] = 90; LangkahSaatIni = 3; break; // S6 NAIK
case 3: SudutTujuan[6] = 90; LangkahSaatIni = 4; break; // S7 NAIK
case 4: SudutTujuan[7] = 90; LangkahSaatIni = 5; break; // S8 NAIK
case 5: SudutTujuan[4] = 20; LangkahSaatIni = 6; break; // S5 TURUN (Bawah)
case 6: SudutTujuan[5] = 20; LangkahSaatIni = 7; break; // S6 TURUN
case 7: SudutTujuan[6] = 20; LangkahSaatIni = 8; break; // S7 TURUN
case 8:
SudutTujuan[7] = 20; // S8 TURUN
LangkahSaatIni = 1; // Kembali ke langkah 1 (looping)
// Logika Transisi: Pindah ke Sub-Mode 2 setelah 7 siklus
static int HitunganSiklusSubMode1 = 0;
HitunganSiklusSubMode1++;
if (HitunganSiklusSubMode1 >= 7) {
SubModeOmbak = 2;
LangkahSaatIni = 0;
HitunganSiklusSubMode1 = 0;
Serial.println("Ombak Sub-Mode Ganti: 2 (Berlawanan)");
}
break;
}
}
// =======================================================
// SUB-MODE 2: BERLAWANAN TERUS-MENERUS (Ombak Dua Arah)
// Servo luar (S5, S8) dan Servo dalam (S6, S7) bergantian
// =======================================================
} else if (SubModeOmbak == 2) {
// Langkah 0: Inisiasi Awal
if (LangkahSaatIni == 0) {
for (int i = 0; i < 4; i++) SudutTujuan[i] = 50;
// Posisi Awal: Luar (S5, S8) Bawah, Dalam (S6, S7) Atas
SudutTujuan[4] = 20; SudutTujuan[7] = 20;
SudutTujuan[5] = 90; SudutTujuan[6] = 90;
LangkahSaatIni = 1;
PemicuUrutanServoTerakhir = waktuSekarang;
}
// Tunggu sampai semua servo mencapai target DAN jeda telah dilewati
if (semuaServoCapaiTujuan && waktuSekarang - PemicuUrutanServoTerakhir >= JEDA_STATIS_OMBAK) {
PemicuUrutanServoTerakhir = waktuSekarang;
// Logika Bergantian: Jika S5 (Luar) sedang di Atas, pindahkan ke Bawah, dan sebaliknya
if (SudutTujuan[4] == 90) {
// Aksi: Luar turun, Dalam naik
SudutTujuan[4] = 20; SudutTujuan[7] = 20;
SudutTujuan[5] = 90; SudutTujuan[6] = 90;
Serial.println("Ombak 2: Luar Bawah, Dalam Atas");
} else {
// Aksi: Luar naik, Dalam turun
SudutTujuan[4] = 90; SudutTujuan[7] = 90;
SudutTujuan[5] = 20; SudutTujuan[6] = 20;
Serial.println("Ombak 2: Luar Atas, Dalam Bawah");
}
// Logika Transisi: Kembali ke Sub-Mode 1 setelah 7 siklus
static int HitunganSiklusSubMode2 = 0;
HitunganSiklusSubMode2++;
if (HitunganSiklusSubMode2 >= 7) {
SubModeOmbak = 1;
LangkahSaatIni = 0; // Kembali ke inisiasi Sub-Mode 1
HitunganSiklusSubMode2 = 0;
Serial.println("Ombak Sub-Mode Ganti: 1 (Saling Susul)");
}
}
}
}
// ------------------------------------------------------------------
// *** SETUP DAN LOOP STANDALONE ***
// ------------------------------------------------------------------
void setup() {
Serial.begin(9600);
Serial.println("--- STANDALONE GERAKAN OMBAK DIMULAI ---");
// Inisiasi Servo
for (int i = 0; i < 8; i++) {
unitServo[i].attach(PinServoTerpasang[i]);
SudutSaatIni[i] = 50;
SudutTujuan[i] = 50; // Awalnya semua netral
unitServo[i].write(SudutSaatIni[i]);
}
Serial.println("Servo Diinisiasi ke 50 derajat.");
// Panggil logika mode Ombak pertama kali untuk inisiasi target
aturModeOmbak();
}
void loop() {
unsigned long waktuSekarang = millis();
// 1. Jalankan Logika Mode Ombak (Menentukan sudut tujuan)
aturModeOmbak();
// 2. LOGIKA PERGERAKAN SERVO (NON-BLOCKING)
// Menggerakkan servo 1 derajat setiap JedaLangkahServo (25ms)
if (waktuSekarang - WaktuLangkahServoTerakhir >= JedaLangkahServo) {
WaktuLangkahServoTerakhir = waktuSekarang;
for (int i = 0; i < 8; i++) {
if (SudutSaatIni[i] != SudutTujuan[i]) {
// Tentukan arah gerakan (maju atau mundur 1 derajat)
int ArahGerak = (SudutTujuan[i] > SudutSaatIni[i]) ? 1 : -1;
SudutSaatIni[i] += ArahGerak;
unitServo[i].write(SudutSaatIni[i]);
}
}
}
}
TERIMA KASIH SAHABAT MINIATUR! Jangan lupa tinggalkan komentar di video kalau kode ini berhasil Anda coba.
Salam dari Sound Akbar Audio 95, Wajak, Malang.
Apakah ada lagi yang bisa saya bantu, Bro? Mungkin Anda ingin merangkai ulang caption TikTok/YouTube Anda?
Komentar
Posting Komentar