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

Postingan populer dari blog ini

Tutorial membuat mixer beam miniatur

Coding arduino untuk beam

Membuat strobo dan whal waser dari led ws