Membuat coding servo beam miniatur circle dan ombak secara otomatis

Gerakan ombak


Membuat coding servo beam miniatur circle dan ombak secara otomatis


Kode ini sangat canggih karena mengontrol 8 servo (untuk 4 set beam/lengan), efek RGB otomatis, dan tombol stop/start dalam dua mode gerakan yang berbeda: circle dan Ombak. mengontrol 4 Beam Otomatis (By akbar mini Sound System )

Kode Arduino ini dirancang untuk mengontrol sistem 4 beam atau head bagian atas yang biasa digunakan pada perlengkapan Sound System Miniatur atau lighting panggung mini. Sistem ini memanfaatkan 8 Servo Motor untuk menggerakkan 4 pasang  (beam), dilengkapi dengan fitur kontrol warna RGB Otomatis dan fungsi toggle Stop/Start.

Ringkasan Fitur Utama

8 Servo untuk mengontrol total 4 pasang beam (2 servo per beam) dengan 2 Mode Otomatis 

MODE_CIRCLE (Gerakan berputar/berantai) dan MODE_OMBAK (Gerakan naik-turun/berlawanan). 

Transisi Otomatis 

Mode akan berganti setelah menyelesaikan 7 siklus (CYCLE_LIMIT). 

RGB Otomatis ,LED RGB berganti warna secara otomatis setiap 10 detik (sahabat juga mengubah jadi 5 dtk / sesuai keinginan) 

Tombol STOP/START, Menghentikan semua gerakan servo di posisi netral (50 derajat) dan mematikan RGB saat STOP. 

A. Konfigurasi Hardware (Definisi Pin)

Sistem ini membutuhkan koneksi ke beberapa komponen:

Servo 1 - 8 pin Digital 3 - 10 untuk 8 Servo terhubung berurutan (Servo 1 ke Pin 3, Servo 8 ke Pin 10). 

LED Merah (R) terhubung ke Analog A1, Untuk kontrol warna RGB (diasumsikan Common Anode). 

LED Hijau (G) terhubung ke Analog A2, Untuk kontrol warna RGB (diasumsikan Common Anode).

LED Biru (B) terhubung ke Analog A3, Untuk kontrol warna RGB (diasumsikan Common Anode). 

Tombol STOP berasa di pin Digital 2, yang Terhubung dengan konfigurasi INPUT_PULLUP (Aktif saat tombol ditekan ke GND). 

Penting: Karena LED RGB terhubung sebagai Common Anode, pin akan disetel ke LOW untuk menyalakan warna, dan HIGH untuk mematikan.

B. Struktur Kode dan Variabel Kunci

1. Variabel Mode dan Kontrol

 * currentActiveMode: Menyimpan mode yang sedang aktif (MODE_SIRKEL atau MODE_OMBAK).

 * servoStepDelay (25ms): Jeda waktu antar pergerakan servo 1 derajat, mengontrol kecepatan umum gerakan.

 * CYCLE_LIMIT (7): Jumlah siklus yang harus diselesaikan setiap mode sebelum berganti.

 * isStopped: Status boolean untuk mengontrol fitur Stop/Start.

2. Logika Pergerakan Servo

Pergerakan halus servo dilakukan tanpa fungsi delay() agar program dapat menjalankan fungsi lain (seperti cek tombol dan RGB) secara bersamaan:

// Bagian dalam fungsi loop()

if (currentMillis - lastServoStepTime >= servoStepDelay) {

    // Logika untuk menggerakkan servo 1 derajat menuju targetAngle

}


C. Detail Logika Per Mode

1. handleModeSirkel()

Mode ini menggerakkan 4 pasang beam (Group 1 hingga Group 4) secara berantai/sirkuler.

 * Group Pairing: Variabel groupPins mendefinisikan pasangan servo untuk setiap beam: { {4, 8}, {3, 7}, {2, 6}, {1, 5} }.

 * Staggered Start: Setiap grup beam memiliki waktu mulai yang tertunda (STAGGER_DELAY = 1000ms) untuk menciptakan efek sirkel yang berkelanjutan.

 * Sequential Movement: Setiap beam bergerak melalui 4 langkah (groupSteps) yang menggerakkan kedua servonya secara bergantian untuk menciptakan efek 'melambai' atau 'berputar'.

2. handleModeOmbak()

Mode ini terbagi menjadi dua sub-mode, fokus pada 4 beam pasangan kedua (servo 4, 5, 6, 7):

 * Sub-Mode 1 (Saling Susul Berantai): Servo 4, 5, 6, dan 7 naik (90 derajat) lalu turun (20 derajat) secara berurutan cepat, menciptakan efek gelombang atau ombak dari satu sisi ke sisi lain.

 * Sub-Mode 2 (Berlawanan Terus-menerus): Pasangan servo luar (4 & 7) dan pasangan servo dalam (5 & 6) bergerak berlawanan (90 vs 20 derajat) secara berulang.

D. Kontrol STOP/START (Tombol Pin D2)

Tombol pada Pin D2 adalah inti dari kontrol pause sistem.

 * Aktivasi: Tombol terhubung ke konfigurasi INPUT_PULLUP, artinya tombol ditekan saat status pin menjadi LOW.

 * Stop State:

   * Variabel isStopped menjadi true.

   * Semua targetAngle servo disetel ke 50 derajat (Netral).

   * LED RGB dimatikan (HIGH pada Common Anode).

 * Start State:

   * isStopped menjadi false.

   * Sistem direset ke MODE_SIRKEL, siap untuk mengulang dari awal.

E. Kontrol RGB Otomatis

Fungsi updateRGB() mengontrol perubahan warna LED RGB:

 * Interval: Warna berganti setiap 10.000 milidetik (10 detik).

 * Skema Warna: Terdapat 6 kombinasi warna yang disimpan dalam array colors: Merah, Hijau, Biru, Kuning, Magenta, dan Cyan.

 * Logika Common Anode: Nilai 1 pada array berarti pin LED harus disetel LOW (ON), dan nilai 0 berarti HIGH (OFF).

Kode ini menunjukkan penerapan yang solid dari konsep multitasking di Arduino, menggunakan timing non-blocking (millis()) untuk mengelola banyak tugas (servo, mode, RGB, tombol) secara simultan.

Sahabat bisa salin code di bawah secara lengkap 

Saat anda salin dan menempelkan di sketch arduino anda urutkan baris dan nomor seperti di code saat anda salin 

====================================

#include <Servo.h>    


// --- 0. DEFINISI NAMA MODE DAN PIN ---

// PIN RGB (Common Anode: HIGH = OFF, LOW = ON)

const int LED_R_PIN = A1; 

const int LED_G_PIN = A2; 

const int LED_B_PIN = A3; 

const int STOP_PIN = 2; // Pin Tombol Stop/Start (INPUT_PULLUP)


const int MODE_SIRKEL = 5; 

const int MODE_OMBAK    = 6; 


// --- 1. OBJEK SERVO ---

// Servo 0-7 akan dihubungkan ke pin Digital 3-10

Servo servo[8];


// --- 2. VARIABEL GLOBAL STATUS & SPEED ---

int currentActiveMode = MODE_SIRKEL; 

int servoStepDelay = 25; // Kecepatan gerakan servo (makin kecil, makin cepat)

int targetAngle[8];

int currentAngle[8];

unsigned long lastServoStepTime = 0;

unsigned long lastModeSwitchTime = 0;

const long MODE_SWITCH_COOLDOWN = 1000; 

unsigned long lastServoSequenceTrigger = 0; 

int currentStep = 0; 


// --- STATUS NETRAL/STOP BARU ---

bool isStopped = false; 

unsigned long lastToggleTime = 0; 

const long DEBOUNCE_DELAY = 200;   


// --- PENGHITUNG PUTARAN (CYCLE) ---

int cycleCounter = 0;

const int CYCLE_LIMIT = 7; // Batas putaran sebelum ganti mode


// --- VARIABEL KHUSUS MODE SIRKEL ---

const int STAGGER_DELAY = 1000; // Jeda antar group mulai

int groupSteps[4] = {0, 0, 0, 0}; 

unsigned long groupStartTime[4] = {0, 0, 0, 0}; 

bool groupIsActive[4] = {false, false, false, false}; 

// Pasangan Servo untuk 4 Beam: {Servo1, Servo2}

const int groupPins[4][2] = { {3, 7}, {2, 6}, {1, 5}, {0, 4} };


// --- VARIABEL KHUSUS MODE OMBAK ---

const int MODE6_STAGGER_DELAY = 650; 

int mode6SubMode = 1; 

bool mode6SubMode2LoopDone = false; 


// --- VARIABEL RGB OTOMATIS ---

unsigned long lastColorChange = 0;

const long COLOR_CHANGE_INTERVAL = 10000; // Ganti warna setiap 10 detik

int currentColorIndex = 0;

// R, G, B (1=ON/LOW, 0=OFF/HIGH untuk Common Anode)

const int colors[][3] = {

    {1, 0, 0}, {0, 1, 0}, {0, 0, 1}, {1, 1, 0}, {1, 0, 1}, {0, 1, 1}

};

const int NUM_COLORS = sizeof(colors) / sizeof(colors[0]);



// --- FUNGSI UTAMA CEK SERVO ---

bool checkAllServosReachedTarget() {

  for (int i = 0; i < 8; i++) {

    if (currentAngle[i] != targetAngle[i]) {

      return false;

    }

  }

  return true;

}


// --- FUNGSI UPDATE RGB (COMMON ANODE) ---

void updateRGB(unsigned long currentMillis) {

  if (currentMillis - lastColorChange >= COLOR_CHANGE_INTERVAL) {

    lastColorChange = currentMillis;

    currentColorIndex = (currentColorIndex + 1) % NUM_COLORS;

    

    int r = colors[currentColorIndex][0];

    int g = colors[currentColorIndex][1];

    int b = colors[currentColorIndex][2];

    

    // Logika Common Anode: 1 (ON) = LOW; 0 (OFF) = HIGH

    digitalWrite(LED_R_PIN, r == 1 ? LOW : HIGH); 

    digitalWrite(LED_G_PIN, g == 1 ? LOW : HIGH); 

    digitalWrite(LED_B_PIN, b == 1 ? LOW : HIGH); 

  }

}


// ------------------------------------------------------------------

// *** LOGIKA MODE SIRKEL ***

// ------------------------------------------------------------------


void handleModeSirkel() {

  unsigned long currentMillis = millis();

  

  if (groupStartTime[0] == 0) {

    unsigned long now = millis();

    for(int i = 0; i < 4; i++) {

      groupStartTime[i] = now + (i * STAGGER_DELAY);

      groupIsActive[i] = false;

    }

  }

  

  for(int i = 0; i < 4; i++) {

    if (!groupIsActive[i] && currentMillis >= groupStartTime[i]) { 

      groupIsActive[i] = true; 

      groupSteps[i] = 0; 

    }

  }

  

  bool modeSirkelLoopDone = true; 


  for(int i = 0; i < 4; i++) {

    if (groupIsActive[i]) {

      modeSirkelLoopDone = false; 

      int servo1 = groupPins[i][0]; int servo2 = groupPins[i][1];

      switch(groupSteps[i]) {

        case 0: targetAngle[servo1] = 5; groupSteps[i] = 1; break;

        case 1: if (currentAngle[servo1] == targetAngle[servo1]) { targetAngle[servo2] = 90; groupSteps[i] = 2; } break;

        case 2: if (currentAngle[servo2] == targetAngle[servo2]) { targetAngle[servo1] = 100; groupSteps[i] = 3; } break;

        case 3: if (currentAngle[servo1] == targetAngle[servo1]) { targetAngle[servo2] = 20; groupSteps[i] = 4; } break;

        case 4: if (currentAngle[servo2] == targetAngle[servo2]) { 

          targetAngle[servo1] = 5; groupSteps[i] = 1; 

          

          if (i == 3) { // Ketika group terakhir (Group 3) mencapai langkah terakhir, hitung sebagai selesai

             groupIsActive[i] = false;

             modeSirkelLoopDone = true;

             cycleCounter++;

          }

        } break;

      }

    }

  }


  // Transisi MODE_SIRKEL -> MODE_OMBAK

  if (cycleCounter >= CYCLE_LIMIT && modeSirkelLoopDone && currentMillis - lastModeSwitchTime > MODE_SWITCH_COOLDOWN) {

    currentActiveMode = MODE_OMBAK;

    cycleCounter = 0; 

    currentStep = 0; 

    lastServoSequenceTrigger = 0;

    mode6SubMode = 1; 

    lastModeSwitchTime = currentMillis;

    

    for(int i = 0; i < 4; i++) groupStartTime[i] = 0;

  }

}


// ------------------------------------------------------------------

// *** LOGIKA MODE OMBAK ***

// ------------------------------------------------------------------


void handleModeOmbak() {

  unsigned long currentMillis = millis();

  bool allServosReachedTarget = checkAllServosReachedTarget();

  

  if (mode6SubMode == 1) { // SUB-MODE 1: Saling Susul Berantai

    

    if (currentStep == 0) { 

      // Servo 0-3 (pasangan pertama) ke posisi netral

      for (int i = 0; i < 4; i++) targetAngle[i] = 50; 

      // Servo 4-7 (pasangan kedua) inisiasi

      targetAngle[4] = 20; targetAngle[5] = 20; targetAngle[6] = 20; targetAngle[7] = 20; 

      lastServoSequenceTrigger = currentMillis; 

      currentStep = 1; 

    }

    unsigned long waveStaggerDelay = servoStepDelay * 30; // Jeda pemicu gerakan wave

    bool subMode1LoopDone = false;

    

    if (currentMillis - lastServoSequenceTrigger >= waveStaggerDelay) {

      lastServoSequenceTrigger = currentMillis;

      switch (currentStep) {

        // Naik

        case 1: targetAngle[4] = 90; currentStep = 2; break; 

        case 2: targetAngle[5] = 90; currentStep = 3; break; 

        case 3: targetAngle[6] = 90; currentStep = 4; break; 

        case 4: targetAngle[7] = 90; currentStep = 5; break; 

        // Turun

        case 5: targetAngle[4] = 20; currentStep = 6; break; 

        case 6: targetAngle[5] = 20; currentStep = 7; break; 

        case 7: targetAngle[6] = 20; currentStep = 8; break; 

        case 8: targetAngle[7] = 20; currentStep = 1; // Ulangi

                subMode1LoopDone = true; break; 

      }

    }

    

    if (subMode1LoopDone && allServosReachedTarget) {

      cycleCounter++;

      if (cycleCounter >= CYCLE_LIMIT) {

        mode6SubMode = 2; 

        cycleCounter = 0; 

        currentStep = 0; 

      }

    }

    

  } else if (mode6SubMode == 2) { // SUB-MODE 2: Berlawanan Terus-menerus


    if (currentStep == 0) { 

      // Servo 0-3 netral

      for (int i = 0; i < 4; i++) targetAngle[i] = 50; 

      // Servo 4 & 7 (luar) di 20, Servo 5 & 6 (dalam) di 90

      targetAngle[4] = 20; targetAngle[7] = 20; targetAngle[5] = 90; targetAngle[6] = 90; 

      currentStep = 1; 

      lastServoSequenceTrigger = currentMillis; 

      mode6SubMode2LoopDone = false; 

    }

    

    if (allServosReachedTarget && currentMillis - lastServoSequenceTrigger >= MODE6_STAGGER_DELAY) {

      lastServoSequenceTrigger = currentMillis;

      

      // Logika bergantian

      if (targetAngle[4] == 90) { // Jika luar di 90, pindah ke 20

        targetAngle[4] = 20; targetAngle[7] = 20; 

        targetAngle[5] = 90; targetAngle[6] = 90; 

      } else { // Jika luar di 20, pindah ke 90

        targetAngle[4] = 90; targetAngle[7] = 90; 

        targetAngle[5] = 20; targetAngle[6] = 20; 

        mode6SubMode2LoopDone = true; // Selesaikan 1 siklus maju-mundur

      }

      currentStep++;

    }

    

    if (mode6SubMode2LoopDone) { 

       cycleCounter++;

       mode6SubMode2LoopDone = false; 

    }


    // Transisi balik ke SIRKEL

    if (cycleCounter >= CYCLE_LIMIT && currentMillis - lastModeSwitchTime > MODE_SWITCH_COOLDOWN) {

      currentActiveMode = MODE_SIRKEL; 

      cycleCounter = 0; 

      currentStep = 0;

      lastServoSequenceTrigger = 0;

      mode6SubMode = 1; 

      

      // Reset semua target angle ke netral (penting untuk transisi bersih)

      for(int i = 0; i < 8; i++) { 

         targetAngle[i] = 50; 

      }

      for(int i = 0; i < 4; i++) { 

         groupStartTime[i] = 0; 

         groupSteps[i] = 0; 

         groupIsActive[i] = false; 

      }

      lastModeSwitchTime = currentMillis;

    }

  }

}


// ------------------------------------------------------------------

// *** FUNGSI SETUP DAN LOOP ***

// ------------------------------------------------------------------


void setup() {

  // Pin Servo: 3, 4, 5, 6, 7, 8, 9, 10

  int assignedServoPins[8] = {3, 4, 5, 6, 7, 8, 9, 10}; 


  for (int i = 0; i < 8; i++) {

    servo[i].attach(assignedServoPins[i]);

    currentAngle[i] = 50; targetAngle[i] = 50; // Posisi netral awal

    servo[i].write(currentAngle[i]);

  }


  // Setup Pin RGB

  pinMode(LED_R_PIN, OUTPUT); 

  pinMode(LED_G_PIN, OUTPUT); 

  pinMode(LED_B_PIN, OUTPUT); 

  

  // Setup Pin Tombol Stop (Pull-up internal diaktifkan)

  pinMode(STOP_PIN, INPUT_PULLUP); 

  

  // Inisiasi RGB agar langsung menyala

  updateRGB(millis() - COLOR_CHANGE_INTERVAL); 


  for(int i = 0; i < 4; i++) { 

    groupSteps[i] = 0; 

    groupIsActive[i] = false; 

    groupStartTime[i] = 0;

  }

}


void loop() {

  unsigned long currentMillis = millis();


  // ************ LOGIKA TOMBOL TOGGLE (STOP/LANJUT) ************

  // Tombol ditekan (LOW) dan debounce delay terlewati

  if (digitalRead(STOP_PIN) == LOW && (currentMillis - lastToggleTime > DEBOUNCE_DELAY)) {

      

      isStopped = !isStopped;

      lastToggleTime = currentMillis; 


      if (isStopped) {

        // --- STOP STATE ---

        for (int i = 0; i < 8; i++) {

          targetAngle[i] = 50; // Semua servo ke posisi netral

        }

        // Matikan RGB (HIGH = OFF untuk Common Anode)

        digitalWrite(LED_R_PIN, HIGH); 

        digitalWrite(LED_G_PIN, HIGH); 

        digitalWrite(LED_B_PIN, HIGH); 

        

      } else {

        // --- START STATE ---

        // Reset mode dan counter

        currentActiveMode = MODE_SIRKEL; 

        cycleCounter = 0; 

        currentStep = 0;

        lastServoSequenceTrigger = 0;

        mode6SubMode = 1; 

        // Reset variabel Mode Sirkel

        for(int i = 0; i < 4; i++) { 

          groupStartTime[i] = 0; 

          groupIsActive[i] = false; 

          groupSteps[i] = 0;

        }

        lastModeSwitchTime = currentMillis; 

      }

  }

  

  if (isStopped) {

    // Jika Stop, hanya izinkan servo bergerak ke netral dan lewati logika mode

    goto SERVO_MOVEMENT; 

  }


  // Hanya jalankan RGB jika tidak sedang Stop

  updateRGB(currentMillis);


  // Jalankan logika mode yang aktif

  switch (currentActiveMode) {

    case MODE_SIRKEL: handleModeSirkel(); break;

    case MODE_OMBAK:  handleModeOmbak();  break;

  }


SERVO_MOVEMENT: 

  // ************ LOGIKA PERGERAKAN SERVO (NON-BLOCKING) ************

  if (currentMillis - lastServoStepTime >= servoStepDelay) {

    lastServoStepTime = currentMillis;

    for (int i = 0; i < 8; i++) {

      if (currentAngle[i] != targetAngle[i]) {

        // Gerakkan 1 derajat menuju target

        int moveDir = (targetAngle[i] > currentAngle[i]) ? 1 : -1;

        currentAngle[i] += moveDir;

        servo[i].write(currentAngle[i]);

      }

    }

  }

}


==================================


Jika Anda berkarya beam miniatur, kode ini sangat cocok untuk memproduksi sound system miniatur atau beam miniatur yang canggih, karena sudah terintegrasi dengan otomatisasi gerak dan pencahayaan yang menarik!


Komentar

Postingan populer dari blog ini

Tutorial membuat mixer beam miniatur

Coding arduino untuk beam

Membuat strobo dan whal waser dari led ws