// =============================================================
// Mesin jahit Shuttlecock Otomatis
// Maju Teknik art
// Versi 1.0b - perbaikan blink Running + status LCD Done
// Dibuat oleh [Eko Andriyanto] - [09 April 2025 / V 1.0b]
// =============================================================
#include <AccelStepper.h> // Library untuk mengontrol stepper motor
#include <LiquidCrystal_I2C.h> // Library untuk LCD I2C
// === Inisialisasi LCD ===
LiquidCrystal_I2C lcd(0x27, 16, 2); // Alamat I2C 0x27, LCD 16x2 (SCL ke A5, SDA ke A4)
// === Pin Stepper Motor ===
#define DIR_A 11 // Pin arah motor A
#define STEP_A 12 // Pin step motor A
#define DIR_B 8 // Pin arah motor B
#define STEP_B 9 // Pin step motor B
AccelStepper motorA(AccelStepper::DRIVER, STEP_A, DIR_A); // Inisialisasi motor A
AccelStepper motorB(AccelStepper::DRIVER, STEP_B, DIR_B); // Inisialisasi motor B
// === Pin Tombol, Potensiometer, Relay, dan Buzzer ===
#define START_BUTTON A1 // Tombol start dengan pull-up
#define RESET_BUTTON A2 // Tombol reset dengan pull-up
#define POT_PIN A0 // Potensiometer untuk kontrol kecepatan
#define RELAY_PIN 10 // Kontrol relay
#define BUZZER_PIN 7 // Buzzer untuk notifikasi
#define STEPS_PER_REV 1600 // Langkah per putaran penuh motor A (1.8° dengan microstepping)
// === Variabel Global ===
bool running = false; // Status mesin sedang berjalan
unsigned long lastStartDebounce = 0; // Waktu debouncing terakhir tombol start
unsigned long lastResetDebounce = 0; // Waktu debouncing terakhir tombol reset
int kokCount = 0; // Counter jumlah shuttlecock yang diproduksi
// === Fungsi untuk Kedipkan Teks "Running" ===
void blinkRunning() {
static bool blinkState = false; // Status kedipan
static unsigned long lastBlink = 0; // Waktu kedipan terakhir
if (millis() - lastBlink > 500) { // Kedip setiap 500ms
lastBlink = millis();
blinkState = !blinkState; // Toggle status kedip
lcd.setCursor(0, 0);
// Tampilkan "Running..." atau spasi kosong untuk efek kedip
lcd.print(blinkState ? "Running..." : " ");
}
}
void setup() {
// Inisialisasi pin mode
pinMode(START_BUTTON, INPUT_PULLUP); // Tombol start dengan internal pull-up
pinMode(RESET_BUTTON, INPUT_PULLUP); // Tombol reset dengan internal pull-up
pinMode(RELAY_PIN, OUTPUT); // Relay sebagai output
pinMode(BUZZER_PIN, OUTPUT); // Buzzer sebagai output
// Konfigurasi kecepatan dan akselerasi motor
motorA.setMaxSpeed(1000); // Kecepatan maksimal motor A
motorA.setAcceleration(1000); // Akselerasi motor A
motorB.setMaxSpeed(5000); // Kecepatan maksimal motor B
motorB.setAcceleration(1000); // Akselerasi motor B
// Inisialisasi LCD
lcd.init();
lcd.backlight(); // Nyalakan backlight LCD
// Tampilkan pesan selamat datang dan status awal
showWelcome();
showInitial();
}
void loop() {
// Cek tombol start ditekan (dengan debouncing)
if (digitalRead(START_BUTTON) == LOW && millis() - lastStartDebounce > 300) {
lastStartDebounce = millis(); // Catat waktu untuk debouncing
running = true; // Set status running
runSequence(); // Jalankan urutan penjahitan
}
// Cek tombol reset ditekan (dengan debouncing)
if (digitalRead(RESET_BUTTON) == LOW && millis() - lastResetDebounce > 300) {
lastResetDebounce = millis(); // Catat waktu untuk debouncing
kokCount = 0; // Reset counter shuttlecock
showStatus("Reset", kokCount); // Tampilkan status reset
delay(1000);
showInitial(); // Kembali ke tampilan awal
}
}
// === Prosedur utama menjalankan urutan tancap bulu ===
void runSequence() {
// Reset posisi motor ke nol
motorA.setCurrentPosition(0);
motorB.setCurrentPosition(0);
digitalWrite(RELAY_PIN, HIGH); // Aktifkan relay
delay(500); // Tunggu 0.5detik
// Definisi sudut dan langkah untuk setiap tahap
struct Step {
float angle; // Sudut putaran motor A
int stepB; // Langkah motor B
};
// Urutan sudut dan langkah untuk 16 titik jahitan + posisi awal/akhir
Step steps[] = {
{ 0, 400 }, { 22.5, 800 }, { 45, 800 }, { 67.5, 800 },
{ 90, 800 }, { 112.5, 800 }, { 135, 800 }, { 157.5, 800 },
{ 180, 800 }, { 202.5, 800 }, { 225, 800 }, { 247.5, 800 },
{ 270, 800 }, { 292.5, 800 }, { 315, 800 }, { 337.5, 800 },
{ 360, 800 } ,{ 385, 400 } // Kembali ke posisi awal
};
// Tampilkan counter shuttlecock di LCD
lcd.clear();
lcd.setCursor(0, 1);
lcd.print("Kok: ");
lcd.print(kokCount);
// Jalankan semua tahap penjahitan
for (int i = 0; i < sizeof(steps) / sizeof(steps[0]); i++) {
moveMotorA(steps[i].angle); // Pindahkan motor A ke sudut tertentu
moveMotorB(steps[i].stepB); // Pindahkan motor B sesuai langkah
}
digitalWrite(RELAY_PIN, LOW); // Matikan relay
beep(); // Bunyikan buzzer
kokCount++; // Tambah counter shuttlecock
showStatus("Done", kokCount); // Tampilkan status selesai
delay(1500); // Tampilkan status selama 1.5 detik
showInitial(); // Kembali ke tampilan awal
}
// === Fungsi Gerakan Motor A Sesuai Sudut ===
void moveMotorA(float angle) {
// Konversi sudut ke langkah motor
int steps = (angle / 360.0) * STEPS_PER_REV;
motorA.moveTo(steps); // Set target posisi
// Jalankan motor sampai mencapai target
while (motorA.distanceToGo() != 0) {
updateSpeed(); // Update kecepatan dari potensiometer
motorA.runSpeed(); // Jalankan motor dengan kecepatan terkini
blinkRunning(); // Kedipkan teks "Running"
}
}
// === Fungsi Gerakan Motor B ===
void moveMotorB(int steps) {
motorB.moveTo(motorB.currentPosition() + steps); // Set target relatif
while (motorB.distanceToGo() != 0) {
updateSpeed(); // Update kecepatan dari potensiometer
motorB.runSpeed(); // Jalankan motor dengan kecepatan terkini
blinkRunning(); // Kedipkan teks "Running"
}
}
// === Update Kecepatan dari Potensiometer ===
void updateSpeed() {
int potValue = analogRead(POT_PIN); // Baca nilai potensiometer
int speed = map(potValue, 0, 1023, 200, 5000); // Map ke rentang kecepatan
motorA.setSpeed(speed); // Set kecepatan motor A
motorB.setSpeed(speed); // Set kecepatan motor B
}
// === Bunyi Buzzer ===
void beep() {
for (int i = 0; i < 2; i++) {
digitalWrite(BUZZER_PIN, HIGH);
delay(200);
digitalWrite(BUZZER_PIN, LOW);
delay(200);
}
}
// === Tampilkan Welcome Message (berkedip 2 kali) ===
void showWelcome() {
for (int i = 0; i < 3; i++) {
lcd.clear();
lcd.setCursor(1, 0);
lcd.print(" Maju Teknik ");
lcd.setCursor(1, 1);
lcd.print("SEWING MACHINE");
delay(600);
lcd.clear();
delay(400);
}
}
// === Tampilkan Status ke LCD ===
void showStatus(String status, int count) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(status); // Tampilkan status (Done/Reset)
lcd.setCursor(0, 1);
lcd.print("Jumlah Kok: ");
lcd.print(count); // Tampilkan jumlah shuttlecock
}
// === Tampilkan Status Awal ===
void showInitial() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Machine Ready"); // Pesan siap
lcd.setCursor(0, 1);
lcd.print("Jumlah Kok: ");
lcd.print(kokCount); // Tampilkan jumlah shuttlecock
}START
RESET
BUZZER
pneumatik