poprawki
This commit is contained in:
+8
-7
@@ -14,10 +14,10 @@ constexpr float WORKSPACE_HEIGHT_MM = 210.0f;
|
||||
constexpr float STEPS_PER_MM_X = 80.0f;
|
||||
constexpr float STEPS_PER_MM_Y = 80.0f;
|
||||
|
||||
constexpr float SPEED_DEFAULT_MM_S = 60.0f;
|
||||
constexpr float SPEED_DEFAULT_MM_S = 50.0f;
|
||||
constexpr float SPEED_MIN_MM_S = 10.0f;
|
||||
constexpr float SPEED_MAX_MM_S = 150.0f;
|
||||
constexpr float ACCEL_MM_S2 = 500.0f;
|
||||
constexpr float ACCEL_MM_S2 = 500.0f; // Przyspieszenie łagodne, np. 2000, za szybko.
|
||||
|
||||
// ── Homing ───────────────────────────────────────────────────────────────────
|
||||
// Krańcówki wyzwalają się gdy głowica jest w PRAWYM GÓRNYM rogu KARTKI.
|
||||
@@ -47,7 +47,7 @@ constexpr int SERVO_SETTLE_MS = 150; // czas opadnięcia serwa [ms]
|
||||
constexpr uint8_t PIN_X_STEP = 26;
|
||||
constexpr uint8_t PIN_X_DIR = 27;
|
||||
constexpr uint8_t PIN_Y_STEP = 14;
|
||||
constexpr uint8_t PIN_Y_DIR = 15; // GPIO15 — bezpieczny zamiennik (GPIO16 niedostępny)
|
||||
constexpr uint8_t PIN_Y_DIR = 15;
|
||||
constexpr uint8_t PIN_STEPPER_EN = 13; // aktywny LOW
|
||||
|
||||
// Wyłączniki krańcowe (INPUT_PULLUP, aktywny LOW — wyzwolony = LOW)
|
||||
@@ -81,8 +81,8 @@ constexpr uint8_t FILENAME_MAX_LEN = 64;
|
||||
// ── Timery UI ────────────────────────────────────────────────────────────────
|
||||
constexpr uint32_t DISPLAY_UPDATE_MS = 200;
|
||||
constexpr uint32_t BUTTON_DEBOUNCE_MS = 50;
|
||||
constexpr uint32_t BOOT_HOLD_MS = 2000;
|
||||
constexpr uint32_t STEPPER_IDLE_TIMEOUT_MS = 5000; // auto-wyłączenie silników po bezczynności [ms], 0=wyłącz
|
||||
constexpr uint32_t BOOT_HOLD_MS = 1000;
|
||||
constexpr uint32_t STEPPER_IDLE_TIMEOUT_MS = 2000; // auto-wyłączenie silników po bezczynności [ms], 0=wyłącz
|
||||
|
||||
// ── Stany aplikacji ───────────────────────────────────────────────────────────
|
||||
enum class AppState : uint8_t {
|
||||
@@ -95,8 +95,9 @@ enum class AppState : uint8_t {
|
||||
ERROR
|
||||
};
|
||||
|
||||
constexpr float TEST_STEP_MM = 1.0f; // krok na jedno naciśnięcie w trybie testowym [mm]
|
||||
constexpr float TEST_SPEED_MM_S = 5.0f; // prędkość w trybie testowym [mm/s]
|
||||
// Ustalenie prędkości dla trybu testowego
|
||||
constexpr float TEST_STEP_MM = 10.0f; //1.0f; // krok na jedno naciśnięcie w trybie testowym [mm]
|
||||
constexpr float TEST_SPEED_MM_S = 40.0f; //5.0f; // prędkość w trybie testowym [mm/s]
|
||||
|
||||
// ── Komendy GCode ────────────────────────────────────────────────────────────
|
||||
enum class GCodeCmd : uint8_t {
|
||||
|
||||
+10
-7
@@ -81,19 +81,21 @@ void display_show_main_menu(uint8_t selected) {
|
||||
if (throttled()) return;
|
||||
markUpdated();
|
||||
|
||||
static const char* const items[3] = {"Drukowanie", "Tryb UART", "Test osi"};
|
||||
static const char* const items[4] = {
|
||||
"Drukowanie", "Tryb UART", "Test osi", "Kalibracja"
|
||||
};
|
||||
|
||||
u8g2.clearBuffer();
|
||||
u8g2.setFont(u8g2_font_6x10_tf);
|
||||
|
||||
drawCentered(0, "CNC Draw - Menu");
|
||||
drawSep(12);
|
||||
drawSep(11);
|
||||
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
uint8_t yTop = 14 + i * 17;
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
uint8_t yTop = 13 + i * 13;
|
||||
if (i == selected) {
|
||||
u8g2.setDrawColor(1);
|
||||
u8g2.drawBox(0, yTop - 1, OLED_W, 13);
|
||||
u8g2.drawBox(0, yTop - 1, OLED_W, 12);
|
||||
u8g2.setDrawColor(0);
|
||||
u8g2.drawStr(4, yTop, items[i]);
|
||||
u8g2.setDrawColor(1);
|
||||
@@ -115,9 +117,10 @@ void display_show_axis_test(char axis, float posX, float posY, bool limitHit) {
|
||||
if (limitHit) {
|
||||
drawCentered(0, "! KRANC OW KA !");
|
||||
drawSep(12);
|
||||
drawCentered(20, "Cofanie...");
|
||||
drawCentered(22, "Ruch zatrzymany");
|
||||
u8g2.setFont(u8g2_font_5x7_tf);
|
||||
drawCentered(38, "czekaj");
|
||||
drawCentered(38, "Cofnij recznie"
|
||||
);
|
||||
} else {
|
||||
char hdr[22];
|
||||
snprintf(hdr, sizeof(hdr), "Test osi: %c", axis);
|
||||
|
||||
@@ -18,9 +18,6 @@ void setup() {
|
||||
motion_init();
|
||||
pen_init();
|
||||
|
||||
display_show_homing();
|
||||
motion_home();
|
||||
|
||||
ui_init(); // startuje w MAIN_MENU
|
||||
}
|
||||
|
||||
|
||||
+15
-11
@@ -68,11 +68,12 @@ void motion_move_to(float x_mm, float y_mm, float feedrate_mm_per_min) {
|
||||
s_lastBaseFeedMmS = feedrate_mm_per_min / 60.0f;
|
||||
applySpeed(s_lastBaseFeedMmS);
|
||||
|
||||
// Kartezjański: każdy silnik steruje tylko swoją osią
|
||||
long sx = (long)(x_mm * STEPS_PER_MM_X) * -HOMING_DIR_X;
|
||||
long sy = (long)(y_mm * STEPS_PER_MM_Y) * -HOMING_DIR_Y;
|
||||
s_stepperX.moveTo(sx);
|
||||
s_stepperY.moveTo(sy);
|
||||
// CoreXY: X = oba silniki ten sam kierunek, Y = oba silniki przeciwne kierunki
|
||||
// motorA.moveTo(X + Y), motorB.moveTo(X - Y)
|
||||
long ax = (long)(x_mm * STEPS_PER_MM_X) * -HOMING_DIR_X;
|
||||
long ay = (long)(y_mm * STEPS_PER_MM_Y) * -HOMING_DIR_Y;
|
||||
s_stepperX.moveTo(ax + ay);
|
||||
s_stepperY.moveTo(ax - ay);
|
||||
}
|
||||
|
||||
bool motion_run() {
|
||||
@@ -125,10 +126,8 @@ void motion_home() {
|
||||
s_stepperY.setMaxSpeed(HOMING_SPEED_MM_S * STEPS_PER_MM_Y);
|
||||
s_stepperY.setAcceleration(ACCEL_MM_S2 * STEPS_PER_MM_Y);
|
||||
|
||||
homeAxisSingle(s_stepperX, HOMING_DIR_X, PIN_LIMIT_X_MIN,
|
||||
WORKSPACE_WIDTH_MM, STEPS_PER_MM_X);
|
||||
homeAxisSingle(s_stepperY, HOMING_DIR_Y, PIN_LIMIT_Y_MIN,
|
||||
WORKSPACE_HEIGHT_MM, STEPS_PER_MM_Y);
|
||||
homeAxisSingle(s_stepperX, HOMING_DIR_X, PIN_LIMIT_X_MIN, WORKSPACE_WIDTH_MM, STEPS_PER_MM_X);
|
||||
homeAxisSingle(s_stepperY, HOMING_DIR_Y, PIN_LIMIT_Y_MIN, WORKSPACE_HEIGHT_MM, STEPS_PER_MM_Y);
|
||||
|
||||
applySpeed(s_lastBaseFeedMmS > 0 ? s_lastBaseFeedMmS : SPEED_DEFAULT_MM_S);
|
||||
s_stepperX.setAcceleration(ACCEL_MM_S2 * STEPS_PER_MM_X);
|
||||
@@ -154,12 +153,17 @@ void motion_disable() {
|
||||
digitalWrite(PIN_STEPPER_EN, HIGH);
|
||||
}
|
||||
|
||||
// CoreXY odwrotność: X = (A+B)/2, Y = (A-B)/2
|
||||
float motion_get_x_mm() {
|
||||
return (float)s_stepperX.currentPosition() / STEPS_PER_MM_X * (-HOMING_DIR_X);
|
||||
long a = s_stepperX.currentPosition();
|
||||
long b = s_stepperY.currentPosition();
|
||||
return (float)(a + b) / 2.0f / STEPS_PER_MM_X * (-HOMING_DIR_X);
|
||||
}
|
||||
|
||||
float motion_get_y_mm() {
|
||||
return (float)s_stepperY.currentPosition() / STEPS_PER_MM_Y * (-HOMING_DIR_Y);
|
||||
long a = s_stepperX.currentPosition();
|
||||
long b = s_stepperY.currentPosition();
|
||||
return (float)(a - b) / 2.0f / STEPS_PER_MM_Y * (-HOMING_DIR_Y);
|
||||
}
|
||||
|
||||
bool motion_any_limit_triggered() {
|
||||
|
||||
+13
-25
@@ -152,14 +152,14 @@ void ui_update() {
|
||||
// ── Menu startowe ──────────────────────────────────────────────────────────
|
||||
case AppState::MAIN_MENU:
|
||||
if (ev == ButtonEvent::UP_PRESS) {
|
||||
s_menuSelected = (s_menuSelected + 2) % 3;
|
||||
s_menuSelected = (s_menuSelected + 3) % 4;
|
||||
display_force_update();
|
||||
} else if (ev == ButtonEvent::DOWN_PRESS) {
|
||||
s_menuSelected = (s_menuSelected + 1) % 3;
|
||||
s_menuSelected = (s_menuSelected + 1) % 4;
|
||||
display_force_update();
|
||||
} else if (ev == ButtonEvent::OK_PRESS) {
|
||||
if (s_menuSelected == 0) {
|
||||
// Drukowanie → inicjuj SD jeśli potrzeba, przejdź do listy
|
||||
// Drukowanie
|
||||
if (!s_sdInited) {
|
||||
if (!sd_init()) {
|
||||
ui_set_error("Blad SD!", "Wloz karte SD");
|
||||
@@ -176,13 +176,20 @@ void ui_update() {
|
||||
uart_mode_init();
|
||||
s_state = AppState::UART_MODE;
|
||||
display_force_update();
|
||||
} else {
|
||||
} else if (s_menuSelected == 2) {
|
||||
// Test osi
|
||||
s_testAxis = 'X';
|
||||
motion_enable();
|
||||
pen_up();
|
||||
s_state = AppState::AXIS_TEST;
|
||||
display_force_update();
|
||||
} else {
|
||||
// Kalibracja
|
||||
display_show_homing();
|
||||
motion_enable();
|
||||
motion_home();
|
||||
display_force_update();
|
||||
display_show_main_menu(s_menuSelected);
|
||||
}
|
||||
}
|
||||
display_show_main_menu(s_menuSelected);
|
||||
@@ -272,27 +279,8 @@ void ui_update() {
|
||||
logAxisTest(lm ? "KRANC!" : "OK ", s_testAxis, posX, posY);
|
||||
}
|
||||
|
||||
// Automatyczne cofanie gdy krańcówka wyzwolona i silniki stoją
|
||||
if (limitActive && motion_is_idle()) {
|
||||
const float backoff = 3.0f;
|
||||
float nx = posX;
|
||||
float ny = posY;
|
||||
if (digitalRead(PIN_LIMIT_X_MIN) == LOW) nx += backoff;
|
||||
if (digitalRead(PIN_LIMIT_X_MAX) == LOW) nx -= backoff;
|
||||
if (digitalRead(PIN_LIMIT_Y_MIN) == LOW) ny += backoff;
|
||||
if (digitalRead(PIN_LIMIT_Y_MAX) == LOW) ny -= backoff;
|
||||
if (nx < 0.0f) nx = 0.0f;
|
||||
if (nx > WORKSPACE_WIDTH_MM) nx = WORKSPACE_WIDTH_MM;
|
||||
if (ny < 0.0f) ny = 0.0f;
|
||||
if (ny > WORKSPACE_HEIGHT_MM) ny = WORKSPACE_HEIGHT_MM;
|
||||
motion_enable();
|
||||
motion_move_to(nx, ny, TEST_SPEED_MM_S * 60.0f);
|
||||
logAxisTest("COFANIE", s_testAxis, nx, ny);
|
||||
display_force_update();
|
||||
}
|
||||
|
||||
// Przyciski aktywne tylko gdy silniki stoją i żadna krańcówka nie wyzwolona
|
||||
if (!limitActive && motion_is_idle()) {
|
||||
// Przyciski aktywne gdy silniki stoją (motion_run blokuje ruch ku krańcówce)
|
||||
if (motion_is_idle()) {
|
||||
if (ev == ButtonEvent::UP_PRESS) {
|
||||
float nx = posX + (s_testAxis == 'X' ? TEST_STEP_MM : 0.0f);
|
||||
float ny = posY + (s_testAxis == 'Y' ? TEST_STEP_MM : 0.0f);
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
#include <AccelStepper.h>
|
||||
|
||||
// ── Pole robocze i Ruch (Zgodnie z plikiem config.h) ────────────────────
|
||||
constexpr float STEPS_PER_MM_X = 80.0f; //
|
||||
constexpr float STEPS_PER_MM_Y = 80.0f; //
|
||||
constexpr float TEST_SPEED_MM_S = 150.0f; // Wolna prędkość testowa z config.h
|
||||
constexpr float ACCEL_MM_S2 = 200.0f; //100.0f; // Łagodne przyspieszenie
|
||||
|
||||
// ── Piny GPIO (Zaktualizowane na podstawie pliku config.h) ─────────────────────
|
||||
constexpr uint8_t PIN_X_STEP = 26; //
|
||||
constexpr uint8_t PIN_X_DIR = 27; //
|
||||
constexpr uint8_t PIN_Y_STEP = 14; //
|
||||
constexpr uint8_t PIN_Y_DIR = 15; //
|
||||
constexpr uint8_t PIN_STEPPER_EN = 13; //
|
||||
|
||||
// Wyłączniki krańcowe (Zaktualizowane piny z config.h)
|
||||
constexpr uint8_t PIN_LIMIT_X_MIN = 36; // LEWA STRONA (DOM X)
|
||||
constexpr uint8_t PIN_LIMIT_X_MAX = 34; // PRAWA STRONA (KONIEC X)
|
||||
constexpr uint8_t PIN_LIMIT_Y_MIN = 39; //
|
||||
constexpr uint8_t PIN_LIMIT_Y_MAX = 35; //
|
||||
|
||||
// Serwo i Przyciski (Zgodnie z config.h)
|
||||
constexpr uint8_t PIN_SERVO = 25; //
|
||||
constexpr int SERVO_ANGLE_UP = 90; //
|
||||
constexpr int SERVO_ANGLE_DOWN = 50; //
|
||||
constexpr uint8_t PIN_BTN_UP = 32; //
|
||||
constexpr uint8_t PIN_BTN_DOWN = 33; //
|
||||
constexpr uint8_t PIN_BTN_OK = 4; //
|
||||
|
||||
// ── Konfiguracja Timera Oszczędzania Energii ─────────────────────────────────
|
||||
constexpr uint32_t STEPPER_TIMEOUT_MS = 2000; // 2 sekundy bezczynności przed odłączeniem prądu
|
||||
|
||||
// Inicjalizacja obiektów dla silników CoreXY / H-Bot
|
||||
AccelStepper motorA(AccelStepper::DRIVER, PIN_X_STEP, PIN_X_DIR);
|
||||
AccelStepper motorB(AccelStepper::DRIVER, PIN_Y_STEP, PIN_Y_DIR);
|
||||
|
||||
// Zmienne pomocnicze
|
||||
bool isPenDown = false;
|
||||
bool lastBtnOkState = HIGH;
|
||||
uint32_t lastActivityTime = 0;
|
||||
bool steppersEnabled = false;
|
||||
|
||||
// Funkcja włączająca prąd w silnikach
|
||||
void enableSteppers() {
|
||||
if (!steppersEnabled) {
|
||||
digitalWrite(PIN_STEPPER_EN, LOW); // LOW = Włączone
|
||||
steppersEnabled = true;
|
||||
Serial.println("[ZASILANIE] Silniki włączone");
|
||||
}
|
||||
lastActivityTime = millis(); // Resetowanie licznika czasu aktywności
|
||||
}
|
||||
|
||||
// Funkcja odcinająca prąd w silnikach (ochrona przed grzaniem)
|
||||
void disableSteppers() {
|
||||
if (steppersEnabled) {
|
||||
motorA.stop();
|
||||
motorB.stop();
|
||||
digitalWrite(PIN_STEPPER_EN, HIGH); // HIGH = Odłączone
|
||||
steppersEnabled = false;
|
||||
Serial.println("[ZASILANIE] Bezczynność 4s -> Odcięcie prądu (Silniki chłodne)");
|
||||
}
|
||||
}
|
||||
|
||||
// Sterowanie serwem (natywne PWM dla ESP32)
|
||||
void setServoAngle(uint8_t pin, int angle) {
|
||||
int dutyCycle = map(angle, 0, 180, 13, 26);
|
||||
analogWrite(pin, dutyCycle);
|
||||
}
|
||||
|
||||
// Sprawdzenie stanu krańcówki (LOW = wciśnięta)
|
||||
bool isLimitTriggered(uint8_t pin) {
|
||||
return digitalRead(pin) == LOW;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
//while (!Serial) delay(10);
|
||||
delay(500);
|
||||
|
||||
// Konfiguracja wejść
|
||||
pinMode(PIN_LIMIT_X_MIN, INPUT);
|
||||
pinMode(PIN_LIMIT_X_MAX, INPUT);
|
||||
pinMode(PIN_LIMIT_Y_MIN, INPUT);
|
||||
pinMode(PIN_LIMIT_Y_MAX, INPUT);
|
||||
|
||||
pinMode(PIN_BTN_UP, INPUT_PULLUP);
|
||||
pinMode(PIN_BTN_DOWN, INPUT_PULLUP);
|
||||
pinMode(PIN_BTN_OK, INPUT_PULLUP);
|
||||
|
||||
// Konfiguracja pinu Enable silników
|
||||
pinMode(PIN_STEPPER_EN, OUTPUT);
|
||||
steppersEnabled = false;
|
||||
enableSteppers();
|
||||
|
||||
// Konfiguracja PWM dla Serwa (50Hz)
|
||||
analogWriteFrequency(PIN_SERVO, 50);
|
||||
setServoAngle(PIN_SERVO, SERVO_ANGLE_UP); // Pisak w górze na starcie
|
||||
|
||||
// Maksymalne prędkości silników
|
||||
motorA.setMaxSpeed(TEST_SPEED_MM_S * STEPS_PER_MM_X);
|
||||
motorB.setMaxSpeed(TEST_SPEED_MM_S * STEPS_PER_MM_Y);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
uint32_t currentTime = millis();
|
||||
|
||||
// ─── 1. OBSŁUGA SERWA (PRZYCISK OK) ──────────────────────────────────────
|
||||
// bool currentBtnOkState = digitalRead(PIN_BTN_OK);
|
||||
|
||||
// if (currentBtnOkState == LOW && lastBtnOkState == HIGH) {
|
||||
// delay(50); // Debounce
|
||||
// if (digitalRead(PIN_BTN_OK) == LOW) {
|
||||
// enableSteppers(); // Aktywność użytkownika wybudza silniki
|
||||
// isPenDown = !isPenDown;
|
||||
|
||||
// if (isPenDown) {
|
||||
// setServoAngle(PIN_SERVO, SERVO_ANGLE_DOWN); //
|
||||
// Serial.println("[SERWO] Pisak opuszczony (DOWN)");
|
||||
// } else {
|
||||
// setServoAngle(PIN_SERVO, SERVO_ANGLE_UP); //
|
||||
// Serial.println("[SERWO] Pisak podniesiony (UP)");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// lastBtnOkState = currentBtnOkState;
|
||||
|
||||
// ─── 2. OBSŁUGA RUCHU OSI X (PRZYCISKI UP / DOWN) ────────────────────────
|
||||
bool upPressed = (digitalRead(PIN_BTN_UP) == LOW);
|
||||
bool downPressed = (digitalRead(PIN_BTN_DOWN) == LOW);
|
||||
|
||||
// if (isLimitTriggered(PIN_LIMIT_X_MAX)){
|
||||
// Serial.println("Krańcówka X_MAX (PRAWA) aktywna!");
|
||||
// }
|
||||
|
||||
// if (isLimitTriggered(PIN_LIMIT_X_MIN)){
|
||||
// Serial.println("Krańcówka X_MIN (LEWA) aktywna!");
|
||||
// }
|
||||
|
||||
// if (isLimitTriggered(PIN_LIMIT_Y_MIN)){
|
||||
// Serial.println("Krańcówka Y_MIN (GORNA) aktywna!");
|
||||
// }
|
||||
|
||||
// if (isLimitTriggered(PIN_LIMIT_Y_MAX)){
|
||||
// Serial.println("Krańcówka X_MAX (DOLNA) aktywna!");
|
||||
// }
|
||||
|
||||
|
||||
if (upPressed && !downPressed) { // Wciśnięty UP
|
||||
enableSteppers();
|
||||
|
||||
// --- RUCH W PRAWO ---
|
||||
// Sprawdzamy, czy nie została osiągnięta prawa krańcówka (X_MAX)
|
||||
if (isLimitTriggered(PIN_LIMIT_X_MAX)) {
|
||||
Serial.println("[STOP] Krańcówka X_MAX (PRAWA) aktywna! Ruch zablokowany.");
|
||||
motorA.stop();
|
||||
motorB.stop();
|
||||
} else {
|
||||
// Oba silniki kręcą się w tę samą stronę (np. wartości dodatnie)
|
||||
motorA.setSpeed(TEST_SPEED_MM_S * STEPS_PER_MM_X);
|
||||
motorB.setSpeed(TEST_SPEED_MM_S * STEPS_PER_MM_Y);
|
||||
motorA.runSpeed();
|
||||
motorB.runSpeed();
|
||||
}
|
||||
}
|
||||
else if (downPressed && !upPressed) { // Przycisk DOWN
|
||||
enableSteppers();
|
||||
|
||||
// --- RUCH W LEWO ---
|
||||
// Sprawdzamy, czy nie została osiągnięta lewa krańcówka (X_MIN)
|
||||
if (isLimitTriggered(PIN_LIMIT_X_MIN)) {
|
||||
Serial.println("[STOP] Krańcówka X_MIN (LEWA) aktywna! Ruch zablokowany.");
|
||||
motorA.stop();
|
||||
motorB.stop();
|
||||
} else {
|
||||
// Oba silniki kręcą się w tę samą stronę, ale w przeciwnym kierunku (ujemne prędkości)
|
||||
motorA.setSpeed(-(TEST_SPEED_MM_S * STEPS_PER_MM_X));
|
||||
motorB.setSpeed(-(TEST_SPEED_MM_S * STEPS_PER_MM_Y));
|
||||
motorA.runSpeed();
|
||||
motorB.runSpeed();
|
||||
}
|
||||
}
|
||||
// else {
|
||||
// // Gdy żaden przycisk nie jest wciśnięty -> wyhamuj silniki
|
||||
// motorA.stop();
|
||||
// motorB.stop();
|
||||
// }
|
||||
|
||||
// ─── 3. AUTOMATYCZNY TIMER USYPIANIA SILNIKÓW ────────────────────────────
|
||||
if (steppersEnabled && (currentTime - lastActivityTime >= STEPPER_TIMEOUT_MS)) {
|
||||
disableSteppers();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user