// =============================================================
// Mesin jahit Shuttlecock Otomatis dengan OLED + Pause Button
// Versi 1.0c - Potensiometer Aktif
// "Sebaik-baik manusia adalah yang paling bermanfaat bagi manusia (lain)."
// =============================================================
#include <AccelStepper.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// === OLED Setting ===
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// === Pin Stepper Motor ===
#define DIR_A 11
#define STEP_A 12
#define DIR_B 8
#define STEP_B 9
AccelStepper motorA(AccelStepper::DRIVER, STEP_A, DIR_A);
AccelStepper motorB(AccelStepper::DRIVER, STEP_B, DIR_B);
// === Pin Tombol, Potensiometer, Relay, dan Buzzer ===
#define START_BUTTON A1
#define RESET_BUTTON A2
#define PAUSE_BUTTON A3
#define POT_PIN A0
#define RELAY_PIN 10
#define BUZZER_PIN 7
#define STEPS_PER_REV 1600 // 1 putaran penuh motorA
// === Variabel Global ===
bool running = false;
bool paused = false;
unsigned long lastStartDebounce = 0;
unsigned long lastResetDebounce = 0;
int kokCount = 0;
// === Fungsi Setup ===
void setup() {
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
while (true); // Gagal inisialisasi OLED
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
animateText("Mesin Jahit", 0, 0, 100);
animateText("Shuttlecock Otomatis", 0, 16, 100);
animateText("Maju teknik Art", 0, 32, 100);
delay(2000);
display.clearDisplay();
display.display();
pinMode(START_BUTTON, INPUT_PULLUP);
pinMode(RESET_BUTTON, INPUT_PULLUP);
pinMode(PAUSE_BUTTON, INPUT_PULLUP);
pinMode(RELAY_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
motorA.setMaxSpeed(30000);
motorA.setAcceleration(10000);
motorB.setMaxSpeed(30000);
motorB.setAcceleration(10000);
showInitial();
}
// === Fungsi Loop ===
void loop() {
if (digitalRead(START_BUTTON) == LOW && !running && millis() - lastStartDebounce > 300) {
lastStartDebounce = millis();
running = true;
paused = false;
runSequence();
running = false;
}
if (digitalRead(RESET_BUTTON) == LOW && millis() - lastResetDebounce > 300) {
lastResetDebounce = millis();
kokCount = 0;
showStatus("Reset", kokCount);
delay(1000);
showInitial();
}
}
// === Fungsi animasi huruf satu per satu ===
void animateText(String text, int x, int y, int delayPerChar) {
display.setCursor(x, y);
for (int i = 0; i < text.length(); i++) {
display.print(text[i]);
display.display();
delay(delayPerChar);
}
}
// === Prosedur utama menjalankan urutan tancap bulu ===
void runSequence() {
motorA.setCurrentPosition(0);
motorB.setCurrentPosition(0);
showStatus("Running", kokCount);
digitalWrite(RELAY_PIN, HIGH);
delay(2000);
struct Step {
float angle;
int stepB;
};
Step steps[] = {
{ 0, 1600 }, { 22.5, 3200 }, { 45, 3200 }, { 67.5, 3200 },
{ 90, 3200 }, { 112.5, 3200 }, { 135, 3200 }, { 157.5, 3200 },
{ 180, 3200 }, { 202.5, 3200 }, { 225, 3200 }, { 247.5, 3200 },
{ 270, 3200 }, { 292.5, 3200 }, { 315, 3200 }, { 337.5, 3200 },
{ 360, 1600 }
};
for (int i = 0; i < sizeof(steps) / sizeof(steps[0]); i++) {
moveMotorA(steps[i].angle);
moveMotorB(steps[i].stepB);
}
digitalWrite(RELAY_PIN, LOW);
beep();
kokCount++;
showStatus("Done", kokCount);
delay(1000);
showInitial();
}
// === Fungsi Gerakan Motor A ===
void moveMotorA(float angle) {
int steps = (angle / 360.0) * STEPS_PER_REV;
motorA.moveTo(steps);
while (motorA.distanceToGo() != 0) {
handlePause();
updateSpeed(); // Update kecepatan real-time
motorA.run();
}
}
// === Fungsi Gerakan Motor B ===
void moveMotorB(int steps) {
motorB.moveTo(motorB.currentPosition() + steps);
while (motorB.distanceToGo() != 0) {
handlePause();
updateSpeed(); // Update kecepatan real-time
motorB.run();
}
}
// === Fungsi Cek dan Handle Pause ===
void handlePause() {
if (digitalRead(PAUSE_BUTTON) == LOW && !paused) {
delay(200); // debounce
paused = true;
showStatus("Paused", kokCount);
}
while (paused) {
if (digitalRead(PAUSE_BUTTON) == LOW) {
delay(200); // debounce
paused = false;
showStatus("Running", kokCount);
}
}
}
// === Update Kecepatan dari Potensiometer ===
void updateSpeed() {
int potValue = analogRead(POT_PIN);
int speed = map(potValue, 0, 1023, 2000, 30000); // Kecepatan maksimum motor
int accel = map(potValue, 0, 1023, 1000, 15000); // Akselerasi juga menyesuaikan
motorA.setMaxSpeed(speed);
motorA.setAcceleration(accel);
motorB.setMaxSpeed(speed);
motorB.setAcceleration(accel);
}
// === Bunyi Buzzer ===
void beep() {
for (int i = 0; i < 2; i++) {
digitalWrite(BUZZER_PIN, HIGH);
delay(200);
digitalWrite(BUZZER_PIN, LOW);
delay(200);
}
}
// === Tampilkan Status ke OLED ===
void showStatus(String status, int count) {
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 0);
display.print(status);
display.setCursor(0, 30);
display.setTextSize(3);
display.print("Kok: ");
display.print(count);
display.display();
}
// === Tampilkan Status Awal ===
void showInitial() {
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 0);
display.print("Mesin Siap");
display.setCursor(0, 30);
display.setTextSize(3);
display.print("Kok: ");
display.print(kokCount);
display.display();
}
ke axis pneumatik
kecepetan stepper
motor
start
reset jumlah kok
Pause