Try to improve backlash handling
This commit is contained in:
90
blinds.ino
90
blinds.ino
@@ -24,6 +24,16 @@ const bool CLEAR_EEPROM = false;
|
||||
|
||||
unsigned long lastMillis = 0;
|
||||
|
||||
// Backlash compensation and hold configuration
|
||||
const int BACKLASH_STEPS = 400; // Tune as needed for your linkage
|
||||
const unsigned long HOLD_OUTPUTS_MS = 300; // Hold time after moves to prevent settling
|
||||
|
||||
// Runtime variables for compensation and holding
|
||||
int approachDir = 0; // Desired final approach direction for current command (-1 or 1)
|
||||
long prepTarget = 0; // First phase target used to preload backlash
|
||||
long finalMoveTarget = 0; // Second phase target: the actual requested position
|
||||
unsigned long holdUntil = 0; // Timestamp when we should release outputs
|
||||
|
||||
struct Config {
|
||||
long openPosition;
|
||||
long closedPosition;
|
||||
@@ -39,6 +49,9 @@ const int OPENING_BLINDS = 2;
|
||||
const int CLOSING_BLINDS = 3;
|
||||
const int IDLE = 4;
|
||||
const int ADJUSTING = 5;
|
||||
const int HOLDING = 6;
|
||||
const int OPENING_PREP = 7;
|
||||
const int CLOSING_PREP = 8;
|
||||
|
||||
int state = SETUP;
|
||||
int previousState = SETUP;
|
||||
@@ -109,18 +122,37 @@ void updateState(int newState) {
|
||||
void openBlinds() {
|
||||
if (!config.blindsOpen && state == IDLE) {
|
||||
Serial.println("Opening Blinds");
|
||||
updateState(OPENING_BLINDS);
|
||||
long baseTarget = config.openPosition;
|
||||
long delta = config.openPosition - config.closedPosition;
|
||||
int openDir = (delta > 0) ? 1 : ((delta < 0) ? -1 : -1); // default to -1 if equal (unlikely)
|
||||
approachDir = openDir;
|
||||
|
||||
// Phase 1: move to preload point on the "closing" side of the final target
|
||||
prepTarget = baseTarget - (approachDir * BACKLASH_STEPS);
|
||||
finalMoveTarget = baseTarget;
|
||||
|
||||
updateState(OPENING_PREP);
|
||||
stepper.enableOutputs();
|
||||
stepper.moveTo(config.openPosition);
|
||||
stepper.moveTo(prepTarget);
|
||||
}
|
||||
}
|
||||
|
||||
void closeBlinds() {
|
||||
if (config.blindsOpen && state == IDLE) {
|
||||
Serial.println("Closing Blinds");
|
||||
updateState(CLOSING_BLINDS);
|
||||
long baseTarget = config.closedPosition;
|
||||
long delta = config.openPosition - config.closedPosition;
|
||||
int openDir = (delta > 0) ? 1 : ((delta < 0) ? -1 : -1);
|
||||
int closeDir = -openDir;
|
||||
approachDir = closeDir;
|
||||
|
||||
// Phase 1: move to preload point on the "opening" side of the final target (opposite of close direction)
|
||||
prepTarget = baseTarget - (approachDir * BACKLASH_STEPS);
|
||||
finalMoveTarget = baseTarget;
|
||||
|
||||
updateState(CLOSING_PREP);
|
||||
stepper.enableOutputs();
|
||||
stepper.moveTo(config.closedPosition);
|
||||
stepper.moveTo(prepTarget);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,20 +245,28 @@ void loop() {
|
||||
delay(10); // <- fixes some issues with WiFi stability
|
||||
break;
|
||||
case SLACK:
|
||||
if (previousState == OPENING_BLINDS) {
|
||||
stepper.move(3000);
|
||||
} else if (previousState == CLOSING_BLINDS) {
|
||||
stepper.move(-3000);
|
||||
} else if (stepper.distanceToGo() == 0) {
|
||||
updateState(IDLE);
|
||||
// Deprecated slack handling; transition to idle once any pending motion completes
|
||||
if (stepper.distanceToGo() == 0) {
|
||||
stepper.disableOutputs();
|
||||
return;
|
||||
}
|
||||
|
||||
updateState(IDLE);
|
||||
} else {
|
||||
stepper.run();
|
||||
|
||||
// Update previous to SLACK until we take up the slack to prevent the stepper from moving forever
|
||||
previousState = state;
|
||||
}
|
||||
break;
|
||||
case OPENING_PREP:
|
||||
case CLOSING_PREP:
|
||||
if (stepper.distanceToGo() != 0) {
|
||||
stepper.run();
|
||||
} else {
|
||||
Serial.println("Open/Close Preparation complete");
|
||||
// Phase 2: approach target from a consistent direction to remove backlash
|
||||
if (state == OPENING_PREP) {
|
||||
updateState(OPENING_BLINDS);
|
||||
} else {
|
||||
updateState(CLOSING_BLINDS);
|
||||
}
|
||||
stepper.moveTo(finalMoveTarget);
|
||||
}
|
||||
break;
|
||||
case OPENING_BLINDS:
|
||||
case CLOSING_BLINDS:
|
||||
@@ -234,17 +274,25 @@ void loop() {
|
||||
if (millis() - lastMillis > 2000) {
|
||||
Serial.print("Speed: ");
|
||||
Serial.print(stepper.speed());
|
||||
Serial.print(" Dist: ");
|
||||
Serial.print(" Remaining Dist: ");
|
||||
Serial.println(stepper.distanceToGo());
|
||||
lastMillis = millis();
|
||||
}
|
||||
stepper.run();
|
||||
} else {
|
||||
stepper.disableOutputs();
|
||||
bool open = state == OPENING_BLINDS;
|
||||
config.blindsOpen = open;
|
||||
sendBlindsUpdate(open);
|
||||
updateState(SLACK);
|
||||
// Hold outputs briefly to prevent settling drift, then transition to IDLE
|
||||
holdUntil = millis() + HOLD_OUTPUTS_MS;
|
||||
updateState(HOLDING);
|
||||
}
|
||||
break;
|
||||
case HOLDING:
|
||||
if (millis() >= holdUntil) {
|
||||
Serial.println("Hold complete, transitioning to idle");
|
||||
stepper.disableOutputs();
|
||||
updateState(IDLE);
|
||||
}
|
||||
break;
|
||||
case ADJUSTING:
|
||||
@@ -259,8 +307,8 @@ void loop() {
|
||||
Serial.print("Finished adjusting to: ");
|
||||
Serial.println(stepper.currentPosition());
|
||||
|
||||
updateState(IDLE);
|
||||
stepper.disableOutputs();
|
||||
holdUntil = millis() + HOLD_OUTPUTS_MS;
|
||||
updateState(HOLDING);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user