Compare commits

...

3 Commits

@@ -18,13 +18,17 @@ int stepSequence[4][4] = {
const int STEPS_PER_REVOLUTION = 2048; // 28BYJ-48 standard (512 steps * 4 gear reduction) const int STEPS_PER_REVOLUTION = 2048; // 28BYJ-48 standard (512 steps * 4 gear reduction)
const float DEGREES_PER_STEP = 360.0 / STEPS_PER_REVOLUTION; const float DEGREES_PER_STEP = 360.0 / STEPS_PER_REVOLUTION;
// Speed Limits (Clamping)
const float MAX_TURN_SPEED = 45.0; // Maximum safe speed in deg/s
const float MIN_TURN_SPEED = 0.1; // Minimum safe speed to avoid div by zero
// --- Global Variables --- // --- Global Variables ---
enum State { MOVE, WAIT }; enum State { MOVE, WAIT };
enum Mode { AUTO, MANUAL }; enum Mode { AUTO, MANUAL };
Mode autoMode = AUTO; // Default: AUTO Mode autoMode = AUTO; // Default: AUTO
float targetAngle = 0.0; // Target angle in degrees float targetAngle = 15.0; // Target angle in degrees
float turnSpeed = 5.0; // Speed in degrees per second float turnSpeed = 45.0; // Speed in degrees per second
State _currState = MOVE; // Default: MOVE State _currState = MOVE; // Default: MOVE
@@ -49,10 +53,6 @@ void setStep(int a, int b, int c, int d) {
} }
void updateStepInterval() { void updateStepInterval() {
if (turnSpeed <= 0) {
_stepInterval = 0.1; // Fallback to avoid div by zero
return;
}
// Calculate steps per second: speed / degrees_per_step // Calculate steps per second: speed / degrees_per_step
float stepsPerSecond = turnSpeed / DEGREES_PER_STEP; float stepsPerSecond = turnSpeed / DEGREES_PER_STEP;
_stepInterval = 1.0 / stepsPerSecond; // Seconds per step _stepInterval = 1.0 / stepsPerSecond; // Seconds per step
@@ -104,6 +104,34 @@ void runStep() {
} }
} }
// --- Serial Output Helpers ---
void printStatus() {
Serial.print("Mode: ");
Serial.print(autoMode == AUTO ? "AUTO" : "MANUAL");
Serial.print(" | State: ");
Serial.print(_currState == MOVE ? "MOVE" : "WAIT");
Serial.print(" | Steps Left: ");
Serial.print(_stepsRemaining);
Serial.print(" | Speed: ");
Serial.print(turnSpeed);
Serial.print(" deg/s | Wait: ");
Serial.print(waitInterval);
Serial.println("s");
}
void printCommandAck(char cmd, String payload) {
Serial.print("> Command '");
Serial.print(cmd);
Serial.print(payload);
Serial.println("' received.");
}
void printError(String msg) {
Serial.print("ERROR: ");
Serial.println(msg);
}
// --- Setup --- // --- Setup ---
void setup() { void setup() {
// Initialize pins // Initialize pins
@@ -116,6 +144,8 @@ void setup() {
Serial.begin(9600); Serial.begin(9600);
while (!Serial) { ; } // Wait for serial port (optional for native USB) while (!Serial) { ; } // Wait for serial port (optional for native USB)
Serial.println("=== Stepper Motor Controller Initialized ===");
// Initial State Setup // Initial State Setup
autoMode = AUTO; autoMode = AUTO;
waitInterval = 8.0; waitInterval = 8.0;
@@ -127,10 +157,16 @@ void setup() {
_waitTime = millis(); _waitTime = millis();
// Initial calculation (move 0 degrees to set defaults) // Initial calculation (move 0 degrees to set defaults)
calculateStepsForAngle(0.0); calculateStepsForAngle(targetAngle);
// Ensure we start in MOVE if we want immediate action, or WAIT if idle
// Based on your logic: "initialized in MOVE state"
_currState = MOVE; _currState = MOVE;
Serial.println("Ready. Commands: m[0|1], a[deg], s[deg/s], i[sec]");
Serial.println(" (Speed clamped between ");
Serial.print(MIN_TURN_SPEED);
Serial.print(" and ");
Serial.print(MAX_TURN_SPEED);
Serial.println(" deg/s)");
printStatus();
} }
// --- Loop --- // --- Loop ---
@@ -140,27 +176,46 @@ void loop() {
String command = Serial.readString(); String command = Serial.readString();
command.trim(); // Remove whitespace command.trim(); // Remove whitespace
if (command.length() < 2) return; // Need at least 'a' + number if (command.length() < 2) {
printError("Invalid command format (too short).");
return;
}
char cmdType = command.charAt(0); char cmdType = command.charAt(0);
String payload = command.substring(1); String payload = command.substring(1);
printCommandAck(cmdType, payload);
switch (cmdType) { switch (cmdType) {
case 'm': case 'm':
// 'm0' for AUTO, 'm1' for MANUAL // 'm0' for AUTO, 'm1' for MANUAL
if (payload.length() > 0) { if (payload.length() > 0) {
char modeChar = payload.charAt(0); char modeChar = payload.charAt(0);
if (modeChar == '0' && autoMode != AUTO) { if (modeChar == '0') {
autoMode = AUTO; if (autoMode != AUTO) {
_currState = MOVE; autoMode = AUTO;
_stepsRemaining = _stepCount; _currState = MOVE;
_stepTime = millis(); _stepsRemaining = _stepCount;
} else if (modeChar == '1' && autoMode != MANUAL) { _stepTime = millis();
autoMode = MANUAL; Serial.println(" -> Mode switched to AUTO. Starting move cycle.");
_currState = MOVE; // Start moving immediately on switch } else {
_stepsRemaining = _stepCount; Serial.println(" -> Already in AUTO mode.");
_stepTime = millis(); }
} else if (modeChar == '1') {
if (autoMode != MANUAL) {
autoMode = MANUAL;
_currState = MOVE; // Start moving immediately on switch
_stepsRemaining = _stepCount;
_stepTime = millis();
Serial.println(" -> Mode switched to MANUAL. Moving once, then waiting.");
} else {
Serial.println(" -> Already in MANUAL mode.");
}
} else {
printError("Invalid mode. Use 'm0' (AUTO) or 'm1' (MANUAL).");
} }
} else {
printError("Missing mode argument (0 or 1).");
} }
break; break;
@@ -168,7 +223,20 @@ void loop() {
// 'a90' -> move 90 degrees // 'a90' -> move 90 degrees
{ {
float angle = payload.toFloat(); float angle = payload.toFloat();
calculateStepsForAngle(angle); if (payload.length() == 0 || (angle == 0 && payload != "0")) {
printError("Invalid angle format.");
} else {
calculateStepsForAngle(angle);
targetAngle = angle;
Serial.print(" -> Moving ");
Serial.print(_stepCount);
Serial.print(" steps (");
Serial.print(targetAngle);
Serial.println(" degrees).");
if (_stepCount == 0) {
Serial.println(" -> No movement required (0 degrees).");
}
}
} }
break; break;
@@ -176,10 +244,27 @@ void loop() {
// 's10' -> 10 deg/s // 's10' -> 10 deg/s
{ {
float speed = payload.toFloat(); float speed = payload.toFloat();
if (speed > 0) { if (payload.length() == 0 || speed <= 0) {
printError("Invalid speed. Must be > 0.");
} else {
turnSpeed = speed; turnSpeed = speed;
// Logic to check if clamping occurred
float actualSpeed = turnSpeed;
if (actualSpeed > MAX_TURN_SPEED) {
turnSpeed = MAX_TURN_SPEED;
Serial.print(" -> WARNING: Speed clamped to max ");
} else if (actualSpeed < MIN_TURN_SPEED) {
turnSpeed = MIN_TURN_SPEED;
Serial.print(" -> WARNING: Speed clamped to min ");
}
updateStepInterval(); updateStepInterval();
// If currently in MOVE, the new interval applies on next step Serial.print(" -> Speed set to ");
Serial.print(turnSpeed);
Serial.print(" deg/s (Step interval: ");
Serial.print(_stepInterval * 1000, 2);
Serial.println(" ms).");
} }
} }
break; break;
@@ -188,12 +273,24 @@ void loop() {
// 'i5' -> 5 seconds wait // 'i5' -> 5 seconds wait
{ {
float interval = payload.toFloat(); float interval = payload.toFloat();
if (interval >= 0) { if (payload.length() == 0 || interval < 0) {
printError("Invalid interval. Must be >= 0.");
} else {
waitInterval = interval; waitInterval = interval;
Serial.print(" -> Wait interval set to ");
Serial.print(waitInterval);
Serial.println(" seconds.");
} }
} }
break; break;
default:
printError("Unknown command. Use m, a, s, or i.");
break;
} }
// Print status after every command for immediate feedback
printStatus();
} }
// --- EXECUTION LOGIC --- // --- EXECUTION LOGIC ---
@@ -202,6 +299,14 @@ void loop() {
if (_currState == MOVE && _stepsRemaining == 0) { if (_currState == MOVE && _stepsRemaining == 0) {
_currState = WAIT; _currState = WAIT;
_waitTime = millis(); _waitTime = millis();
Serial.println("--- State: MOVE -> WAIT ---");
if (autoMode == AUTO) {
Serial.print(" Waiting ");
Serial.print(waitInterval);
Serial.println(" seconds before next cycle...");
} else {
Serial.println(" Waiting indefinitely for new command (MANUAL mode).");
}
} }
// 2. Check if we should restart in AUTO mode // 2. Check if we should restart in AUTO mode
@@ -210,6 +315,10 @@ void loop() {
_currState = MOVE; _currState = MOVE;
_stepsRemaining = _stepCount; _stepsRemaining = _stepCount;
_stepTime = millis(); // Reset step timer to prevent burst _stepTime = millis(); // Reset step timer to prevent burst
Serial.println("--- State: WAIT -> MOVE ---");
Serial.print(" Auto-restart! Moving ");
Serial.print(_stepsRemaining);
Serial.println(" steps.");
} }
// If MANUAL: Stay in WAIT indefinitely until new command // If MANUAL: Stay in WAIT indefinitely until new command
} }
@@ -221,6 +330,14 @@ void loop() {
runStep(); runStep();
_stepTime = currentTime; _stepTime = currentTime;
_stepsRemaining--; _stepsRemaining--;
// Optional: Print progress every 10 steps to avoid spam
// if (_stepCount > 0 && (_stepCount - _stepsRemaining) % 10 == 0) {
// Serial.print(" Step: ");
// Serial.print(_stepCount - _stepsRemaining);
// Serial.print("/");
// Serial.println(_stepCount);
// }
} }
} }
} }