From 9be415302d74445f1ed71913a8e011139a8e2216 Mon Sep 17 00:00:00 2001 From: mwood77 <43637076+mwood77@users.noreply.github.com> Date: Tue, 15 Oct 2024 12:30:56 +0200 Subject: [PATCH 1/4] basic stepper motor control w/ TMC2209 --- platformio.ini | 4 +- src/platformio/osww-server/src/main.cpp | 20 +++++-- .../osww-server/src/utils/MotorControl.cpp | 53 +++++++++++++++++-- 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/platformio.ini b/platformio.ini index 9772eeb..d3e4f94 100644 --- a/platformio.ini +++ b/platformio.ini @@ -21,8 +21,9 @@ build_src_filter = +<*> -<./angular/> board_build.filesystem = littlefs check_tool = cppcheck, clangtidy build_flags = - -D OLED_ENABLED=false + -D OLED_ENABLED=true -D PWM_MOTOR_CONTROL=false + -D STEPPER_MOTOR_CONTROL=true -D HOME_ASSISTANT_ENABLED=false check_flags = clangtidy: -fix-errors,--format-style=google @@ -36,3 +37,4 @@ lib_deps = adafruit/Adafruit SSD1306@^2.5.9 electromagus/ESPMX1508@^1.0.5 dawidchyrzynski/home-assistant-integration@^2.1.0 + janelia-arduino/TMC2209@^9.4.2 diff --git a/src/platformio/osww-server/src/main.cpp b/src/platformio/osww-server/src/main.cpp index 528577a..8946eb0 100644 --- a/src/platformio/osww-server/src/main.cpp +++ b/src/platformio/osww-server/src/main.cpp @@ -94,11 +94,19 @@ AsyncWebServer server(80); HTTPClient http; WiFiClient client; ESP32Time rtc; -String winderooVersion = "3.0.0"; +String winderooVersion = "3.1.0"; -#if PWM_MOTOR_CONTROL +#if PWM_MOTOR_CONTROL && STEPPER_MOTOR_CONTROL + #error "You can only have one optional motor control method enabled at a time. You must disable either PWM_MOTOR_CONTROL or STEPPER_MOTOR_CONTROL in the platformio.ini file." +#endif + +// PWM control +#if PWM_MOTOR_CONTROL && !STEPPER_MOTOR_CONTROL MotorControl motor(directionalPinA, directionalPinB, true); -#else +#endif + +// Stepper motor control || Regular DC motor control +#if STEPPER_MOTOR_CONTROL && !PWM_MOTOR_CONTROL || !STEPPER_MOTOR_CONTROL && !WM_MOTOR_CONTROL MotorControl motor(directionalPinA, directionalPinB); #endif @@ -1184,6 +1192,11 @@ void setup() display.invertDisplay(OLED_INVERT_SCREEN); display.setRotation(rotate); drawNotification("Winderoo"); + + + String savedNetworkMessage[2] = {"Winderoo build", "v" + winderooVersion}; + drawMultiLineText(savedNetworkMessage); + delay(1200); } String savedNetworkMessage[2] = {"Connecting to", "saved network..."}; @@ -1302,6 +1315,7 @@ void setup() drawNotification("Starting webserver..."); startWebserver(); + delay(750); // delay to show notification if (strcmp(userDefinedSettings.status.c_str(), "Winding") == 0) { diff --git a/src/platformio/osww-server/src/utils/MotorControl.cpp b/src/platformio/osww-server/src/utils/MotorControl.cpp index 896f503..4765ee7 100644 --- a/src/platformio/osww-server/src/utils/MotorControl.cpp +++ b/src/platformio/osww-server/src/utils/MotorControl.cpp @@ -7,12 +7,44 @@ int motorSpeed = 145; #endif +#if STEPPER_MOTOR_CONTROL + #include + + // Instantiate TMC2209 + TMC2209 stepper_driver; + HardwareSerial & serial_stream = Serial1; + + const int RX_PIN = 5; + const int TX_PIN = 26; + const uint8_t HARDWARE_ENABLE_PIN = 4; + + const long SERIAL_BAUD_RATE = 115200; + const int32_t RUN_VELOCITY = 20000; + const int32_t STOP_VELOCITY = 0; + + + // current values may need to be reduced to prevent overheating depending on + // specific motor and power supply voltage + const uint8_t RUN_CURRENT_PERCENT = 100; + +#endif + MotorControl::MotorControl(int pinA, int pinB, bool pwmMotorControl) { + #if STEPPER_MOTOR_CONTROL + stepper_driver.setup(serial_stream, SERIAL_BAUD_RATE, TMC2209::SERIAL_ADDRESS_0, RX_PIN, TX_PIN); + stepper_driver.setHardwareEnablePin(HARDWARE_ENABLE_PIN); + stepper_driver.setRunCurrent(RUN_CURRENT_PERCENT); + stepper_driver.enableCoolStep(); + stepper_driver.enable(); + + _motorDirection = 0; + #else _pinA = pinA; _pinB = pinB; _motorDirection = 0; _pwmMotorControl = pwmMotorControl; + #endif } void MotorControl::clockwise() @@ -20,6 +52,8 @@ void MotorControl::clockwise() #if PWM_MOTOR_CONTROL MX1508 pwmControl(_pinA, _pinB, CH1, CH2); pwmControl.motorGo(motorSpeed); + #elif STEPPER_MOTOR_CONTROL + stepper_driver.moveAtVelocity(RUN_VELOCITY); #else digitalWrite(_pinA, HIGH); digitalWrite(_pinB, LOW); @@ -32,6 +66,8 @@ void MotorControl::countClockwise() #if PWM_MOTOR_CONTROL MX1508 pwmControl(_pinA, _pinB, CH1, CH2); pwmControl.motorRev(motorSpeed); + #elif STEPPER_MOTOR_CONTROL + stepper_driver.moveAtVelocity(RUN_VELOCITY); #else digitalWrite(_pinA, LOW); digitalWrite(_pinB, HIGH); @@ -44,6 +80,8 @@ void MotorControl::stop() #if PWM_MOTOR_CONTROL MX1508 pwmControl(_pinA, _pinB, CH1, CH2); pwmControl.motorBrake(); + #elif STEPPER_MOTOR_CONTROL + stepper_driver.moveAtVelocity(STOP_VELOCITY); #else digitalWrite(_pinA, LOW); digitalWrite(_pinB, LOW); @@ -53,16 +91,21 @@ void MotorControl::stop() void MotorControl::determineMotorDirectionAndBegin() { - // @todo - investigate if this is still needed - // stop(); - if (_motorDirection) { - clockwise(); + #if STEPPER_MOTOR_CONTROL + stepper_driver.disableInverseMotorDirection(); + #else + clockwise(); + #endif } else { - countClockwise(); + #if STEPPER_MOTOR_CONTROL + stepper_driver.enableInverseMotorDirection(); + #else + countClockwise(); + #endif } } From d42f859640dba829cc9e11ad21645ee23983cbd0 Mon Sep 17 00:00:00 2001 From: mwood77 <43637076+mwood77@users.noreply.github.com> Date: Thu, 24 Oct 2024 12:47:12 +0200 Subject: [PATCH 2/4] refactor to step / dir pins --- .../osww-server/src/utils/MotorControl.cpp | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/platformio/osww-server/src/utils/MotorControl.cpp b/src/platformio/osww-server/src/utils/MotorControl.cpp index 4765ee7..6bf79a2 100644 --- a/src/platformio/osww-server/src/utils/MotorControl.cpp +++ b/src/platformio/osww-server/src/utils/MotorControl.cpp @@ -10,40 +10,43 @@ #if STEPPER_MOTOR_CONTROL #include - // Instantiate TMC2209 - TMC2209 stepper_driver; - HardwareSerial & serial_stream = Serial1; - - const int RX_PIN = 5; - const int TX_PIN = 26; - const uint8_t HARDWARE_ENABLE_PIN = 4; + HardwareSerial & serial_stream = Serial2; - const long SERIAL_BAUD_RATE = 115200; + const uint8_t STEP_PIN = 17; + const uint8_t DIRECTION_PIN = 16; + const int32_t RUN_VELOCITY = 20000; const int32_t STOP_VELOCITY = 0; - + const uint16_t HALF_STEP_DURATION_MICROSECONDS = 10; // current values may need to be reduced to prevent overheating depending on // specific motor and power supply voltage const uint8_t RUN_CURRENT_PERCENT = 100; + // Instantiate TMC2209 + TMC2209 stepper_driver; + #endif MotorControl::MotorControl(int pinA, int pinB, bool pwmMotorControl) { #if STEPPER_MOTOR_CONTROL - stepper_driver.setup(serial_stream, SERIAL_BAUD_RATE, TMC2209::SERIAL_ADDRESS_0, RX_PIN, TX_PIN); - stepper_driver.setHardwareEnablePin(HARDWARE_ENABLE_PIN); + + stepper_driver.setup(serial_stream); + + pinMode(STEP_PIN, OUTPUT); + pinMode(DIRECTION_PIN, OUTPUT); + stepper_driver.setRunCurrent(RUN_CURRENT_PERCENT); stepper_driver.enableCoolStep(); stepper_driver.enable(); _motorDirection = 0; #else - _pinA = pinA; - _pinB = pinB; - _motorDirection = 0; - _pwmMotorControl = pwmMotorControl; + _pinA = pinA; + _pinB = pinB; + _motorDirection = 0; + _pwmMotorControl = pwmMotorControl; #endif } @@ -53,7 +56,8 @@ void MotorControl::clockwise() MX1508 pwmControl(_pinA, _pinB, CH1, CH2); pwmControl.motorGo(motorSpeed); #elif STEPPER_MOTOR_CONTROL - stepper_driver.moveAtVelocity(RUN_VELOCITY); + // stepper_driver.moveAtVelocity(RUN_VELOCITY); + stepper_driver.moveUsingStepDirInterface(); #else digitalWrite(_pinA, HIGH); digitalWrite(_pinB, LOW); @@ -67,7 +71,8 @@ void MotorControl::countClockwise() MX1508 pwmControl(_pinA, _pinB, CH1, CH2); pwmControl.motorRev(motorSpeed); #elif STEPPER_MOTOR_CONTROL - stepper_driver.moveAtVelocity(RUN_VELOCITY); + // stepper_driver.moveAtVelocity(RUN_VELOCITY); + stepper_driver.moveUsingStepDirInterface(); #else digitalWrite(_pinA, LOW); digitalWrite(_pinB, HIGH); @@ -82,6 +87,7 @@ void MotorControl::stop() pwmControl.motorBrake(); #elif STEPPER_MOTOR_CONTROL stepper_driver.moveAtVelocity(STOP_VELOCITY); + stepper_driver.moveUsingStepDirInterface(); #else digitalWrite(_pinA, LOW); digitalWrite(_pinB, LOW); From cd794ce462405da354aed6a50034968080dfefb5 Mon Sep 17 00:00:00 2001 From: mwood77 <43637076+mwood77@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:57:44 +0100 Subject: [PATCH 3/4] change to different TMC driver and implement --- platformio.ini | 3 +- src/platformio/osww-server/src/main.cpp | 11 ++ .../osww-server/src/utils/MotorControl.cpp | 153 ++++++++++++++---- .../osww-server/src/utils/MotorControl.h | 10 ++ 4 files changed, 143 insertions(+), 34 deletions(-) diff --git a/platformio.ini b/platformio.ini index d3e4f94..88d4d36 100644 --- a/platformio.ini +++ b/platformio.ini @@ -37,4 +37,5 @@ lib_deps = adafruit/Adafruit SSD1306@^2.5.9 electromagus/ESPMX1508@^1.0.5 dawidchyrzynski/home-assistant-integration@^2.1.0 - janelia-arduino/TMC2209@^9.4.2 + teemuatlut/TMCStepper@^0.7.3 + plerup/EspSoftwareSerial@^8.2.0 diff --git a/src/platformio/osww-server/src/main.cpp b/src/platformio/osww-server/src/main.cpp index 8946eb0..e39a9df 100644 --- a/src/platformio/osww-server/src/main.cpp +++ b/src/platformio/osww-server/src/main.cpp @@ -397,6 +397,17 @@ unsigned long calculateWindingTime() */ void beginWindingRoutine() { + + + if (userDefinedSettings.direction == "CW" ) + { + motor.setMotorDirection(1); + } + else if (userDefinedSettings.direction == "CCW") + { + motor.setMotorDirection(0); + } + startTimeEpoch = rtc.getEpoch(); previousEpoch = startTimeEpoch; routineRunning = true; diff --git a/src/platformio/osww-server/src/utils/MotorControl.cpp b/src/platformio/osww-server/src/utils/MotorControl.cpp index 6bf79a2..ed4a2fa 100644 --- a/src/platformio/osww-server/src/utils/MotorControl.cpp +++ b/src/platformio/osww-server/src/utils/MotorControl.cpp @@ -1,5 +1,8 @@ #include "MotorControl.h" +// Define the static instance variable +MotorControl* MotorControl::instance = nullptr; + #if PWM_MOTOR_CONTROL #include #define CH1 1 @@ -7,40 +10,45 @@ int motorSpeed = 145; #endif -#if STEPPER_MOTOR_CONTROL - #include - - HardwareSerial & serial_stream = Serial2; +#ifdef STEPPER_MOTOR_CONTROL + #include + #include + + const uint16_t EN_PIN = 4; // Enable + const uint16_t DIR_PIN = 16; // Direction + const uint16_t STEP_PIN = 17; // Step + + const signed long RUN_VELOCITY = 20000; + const signed long STOP_VELOCITY = 0; + + #define SW_RX 3 // TMC2208/TMC2224 SoftwareSerial receive pin + #define SW_TX 1 // TMC2208/TMC2224 SoftwareSerial transmit pin + #define SERIAL_PORT Serial1 // TMC2208/TMC2224 HardwareSerial port + #define DRIVER_ADDRESS 0b00 // TMC2209 Driver address according to MS1 and MS2 + + const uint16_t R_SENSE = 0.11f; // TMC2209 - SilentStepStick series use 0.11 - const uint8_t STEP_PIN = 17; - const uint8_t DIRECTION_PIN = 16; - - const int32_t RUN_VELOCITY = 20000; - const int32_t STOP_VELOCITY = 0; - const uint16_t HALF_STEP_DURATION_MICROSECONDS = 10; + SoftwareSerial softwareSerial(SW_RX, SW_TX); // Create SoftwareSerial object + TMC2208Stepper driver = TMC2208Stepper(&softwareSerial, R_SENSE); // Use SoftwareSerial object - // current values may need to be reduced to prevent overheating depending on - // specific motor and power supply voltage - const uint8_t RUN_CURRENT_PERCENT = 100; + // For non-blocking stepper movement + hw_timer_t *timer = NULL; + volatile bool stepPinState = LOW; + static bool timerConfigured = false; - // Instantiate TMC2209 - TMC2209 stepper_driver; + // For stepper timing control (RPM) + uint16_t microSteps = 8; + uint16_t rmsCurrent = 800; + uint64_t timerMicroSecondInterval = 400; // 937 microseconds for 40 RPM / 400 microseconds for 100 RPM #endif MotorControl::MotorControl(int pinA, int pinB, bool pwmMotorControl) { - #if STEPPER_MOTOR_CONTROL + #ifdef STEPPER_MOTOR_CONTROL + instance = this; + stepperSetup(); - stepper_driver.setup(serial_stream); - - pinMode(STEP_PIN, OUTPUT); - pinMode(DIRECTION_PIN, OUTPUT); - - stepper_driver.setRunCurrent(RUN_CURRENT_PERCENT); - stepper_driver.enableCoolStep(); - stepper_driver.enable(); - _motorDirection = 0; #else _pinA = pinA; @@ -50,14 +58,76 @@ MotorControl::MotorControl(int pinA, int pinB, bool pwmMotorControl) #endif } +void MotorControl::stepperSetup() { + + softwareSerial.begin(9600); + + pinMode(EN_PIN, OUTPUT); + pinMode(STEP_PIN, OUTPUT); + pinMode(DIR_PIN, OUTPUT); + digitalWrite(EN_PIN, LOW); + + driver.begin(); + driver.toff(5); // Enables driver in software + driver.rms_current(rmsCurrent); // Set motor RMS current in mA + driver.microsteps(microSteps); // Set microsteps to 1/8th because reasons + driver.stealth(); // Enable stealthChop +} + +// This private function is used to toggle the step pin by the timer +void IRAM_ATTR MotorControl::onTimer() +{ + digitalWrite(STEP_PIN, stepPinState); + stepPinState = !stepPinState; +} + +void IRAM_ATTR MotorControl::onTimerStatic() +{ + instance->onTimer(); +} + +void killTimer() +{ + Serial.println("[INFO] - Killing timer"); + + timerAlarmDisable(timer); // Disable the timer to stop + timerDetachInterrupt(timer); // Detach the interrupt + timerEnd(timer); // End the timer + + stepPinState = LOW; + digitalWrite(STEP_PIN, stepPinState); + + timer = NULL; + timerConfigured = false; +} + +void MotorControl::configureHardwareTimer() +{ + if (!timerConfigured) + { + timer = timerBegin(0, 80, true); // Timer 0, prescaler 80 (1 MHz clock) + timerAttachInterrupt(timer, &onTimerStatic, true); // Attach onTimer function to timer + timerAlarmWrite(timer, timerMicroSecondInterval, true); // Set timer interval 937 microseconds for 40 RPM + timerAlarmEnable(timer); // Enable the timer + timerConfigured = true; + } + +} + void MotorControl::clockwise() { #if PWM_MOTOR_CONTROL MX1508 pwmControl(_pinA, _pinB, CH1, CH2); pwmControl.motorGo(motorSpeed); #elif STEPPER_MOTOR_CONTROL - // stepper_driver.moveAtVelocity(RUN_VELOCITY); - stepper_driver.moveUsingStepDirInterface(); + // Set the direction pin + if (timerConfigured) timerAlarmDisable(timer); + + digitalWrite(DIR_PIN, LOW); + delay(10); + + if (timerConfigured) timerAlarmEnable(timer); + // Non-blocking step handling is now through the timer function; "configureHardwareTimer()" #else digitalWrite(_pinA, HIGH); digitalWrite(_pinB, LOW); @@ -71,8 +141,14 @@ void MotorControl::countClockwise() MX1508 pwmControl(_pinA, _pinB, CH1, CH2); pwmControl.motorRev(motorSpeed); #elif STEPPER_MOTOR_CONTROL - // stepper_driver.moveAtVelocity(RUN_VELOCITY); - stepper_driver.moveUsingStepDirInterface(); + // Set the direction pin + if (timerConfigured) timerAlarmDisable(timer); + + digitalWrite(DIR_PIN, HIGH); + delay(10); + + if (timerConfigured) timerAlarmEnable(timer); + // Non-blocking step handling is now through the timer function; "configureHardwareTimer()" #else digitalWrite(_pinA, LOW); digitalWrite(_pinB, HIGH); @@ -86,8 +162,10 @@ void MotorControl::stop() MX1508 pwmControl(_pinA, _pinB, CH1, CH2); pwmControl.motorBrake(); #elif STEPPER_MOTOR_CONTROL - stepper_driver.moveAtVelocity(STOP_VELOCITY); - stepper_driver.moveUsingStepDirInterface(); + if (timerConfigured) + { + killTimer(); + } #else digitalWrite(_pinA, LOW); digitalWrite(_pinB, LOW); @@ -100,7 +178,10 @@ void MotorControl::determineMotorDirectionAndBegin() if (_motorDirection) { #if STEPPER_MOTOR_CONTROL - stepper_driver.disableInverseMotorDirection(); + clockwise(); // We call this for logging purposes + if (!timerConfigured) { + configureHardwareTimer(); + } #else clockwise(); #endif @@ -108,7 +189,10 @@ void MotorControl::determineMotorDirectionAndBegin() else { #if STEPPER_MOTOR_CONTROL - stepper_driver.enableInverseMotorDirection(); + countClockwise(); // We call this for logging purposes + if (!timerConfigured) { + configureHardwareTimer(); + } #else countClockwise(); #endif @@ -123,4 +207,7 @@ int MotorControl::getMotorDirection() void MotorControl::setMotorDirection(int direction) { _motorDirection = direction; + + Serial.print("[INFO] - MOTOR CONTROLLER - Setting direction to: "); + Serial.println(_motorDirection ? "CW" : "CCW"); } diff --git a/src/platformio/osww-server/src/utils/MotorControl.h b/src/platformio/osww-server/src/utils/MotorControl.h index b47c6a7..04dc6aa 100644 --- a/src/platformio/osww-server/src/utils/MotorControl.h +++ b/src/platformio/osww-server/src/utils/MotorControl.h @@ -12,6 +12,16 @@ class MotorControl int _motorDirection; bool _pwmMotorControl; + void stepperSetup(); + + static void IRAM_ATTR onTimerStatic(); // Add this line + + void onTimer(); + + void configureHardwareTimer(); + + static MotorControl* instance; // Add this line + public: MotorControl(int _pinA, int _pinB, bool pwmMotorControl = false); From 3fd64763b4b913d95050ee8f71d7cf3e56797515 Mon Sep 17 00:00:00 2001 From: mwood77 <43637076+mwood77@users.noreply.github.com> Date: Sat, 21 Dec 2024 14:44:14 +0100 Subject: [PATCH 4/4] `DIR_PIN` was set incorrectly, causing the motor to turn in the opposite direction of what was indicated & increase microSteps and rmsCurrent --- src/platformio/osww-server/src/utils/MotorControl.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/platformio/osww-server/src/utils/MotorControl.cpp b/src/platformio/osww-server/src/utils/MotorControl.cpp index ed4a2fa..d4a103c 100644 --- a/src/platformio/osww-server/src/utils/MotorControl.cpp +++ b/src/platformio/osww-server/src/utils/MotorControl.cpp @@ -37,8 +37,8 @@ MotorControl* MotorControl::instance = nullptr; static bool timerConfigured = false; // For stepper timing control (RPM) - uint16_t microSteps = 8; - uint16_t rmsCurrent = 800; + uint16_t microSteps = 4; + uint16_t rmsCurrent = 600; uint64_t timerMicroSecondInterval = 400; // 937 microseconds for 40 RPM / 400 microseconds for 100 RPM #endif @@ -123,7 +123,7 @@ void MotorControl::clockwise() // Set the direction pin if (timerConfigured) timerAlarmDisable(timer); - digitalWrite(DIR_PIN, LOW); + digitalWrite(DIR_PIN, HIGH); delay(10); if (timerConfigured) timerAlarmEnable(timer); @@ -144,7 +144,7 @@ void MotorControl::countClockwise() // Set the direction pin if (timerConfigured) timerAlarmDisable(timer); - digitalWrite(DIR_PIN, HIGH); + digitalWrite(DIR_PIN, LOW); delay(10); if (timerConfigured) timerAlarmEnable(timer);