Arduino CNC Shield v3 Servo's not Working

Hi guys (and gals), this is my first time using this form. I have been working on a CNC Coil Winding machine for the last six months (Off and on). Its been a fun project with many hurtles, a few set backs, ect. But overall, well worth the effort. And I mean that. I will give the specs at the end when I get done explaining what is going on.

I just got everything together last night and tried it for the first time. When I did, the servos (kicked) as the power was turned on. This seems to be a normal thing (function) when power is turned on. However, when I set up my coil settings and press my start button, nothing happened. No steppers running, ect. No motion.

The Specs,
1 Arduino Mega 2560
1 CNC Shield v3
2 A4988 Drivers
1 LRS-150-24 (24volts 5amps)
1 Buck Converter (set at 9.6 volts for the Arduino)
2 NEMA 17 Stepper Motors (Full step = 200steps per rev)
1 3.5 TFT SPI Touchscreen Module
1 TXS0108E High Speed Full Duplex 8 Channel Level Conversion Module

I went ahead and did a deep dive on the web to see what I could do to get this to work. I check my Vref on the A4988 driver. That was good checking out at .75 and the other at .78. Check the voltage from the Vmot and GND, 24 volts from the PS (Power Supply). Which should be in the range of 12 to 36 for the CNC Shield. I have yet to check the fuse but with the voltage going to the driver, the fuse should be good. Ill check this later today to make sure.

The funny thing was, when I checked the heatsinks on the driver, they where not hot at all. Something else happened when I was doing this as well. One of the sides of the heatsink touched one of the pins on the side of the driver when I was check them. One of my servos start to move for a second.

Im not sure what else to check on CNC Shield. But with that done, I went ahead and tried some test scripts to see if it was anything to do with a library file or some other device causing a problem. Still doing some testing on this. But the test scripts did not work either. I'm at a lose.

I have an extra CNC Shield, Adruino Uno, and a few extra drivers to try.

When I get a chance, ill post a video or some images of the devices. Anything you guys and gals can offer in information would be great. Not sure what else could go wrong at this point.

Below is the code that I have so far for my script. It is still in development but its serves it purpose. Everything inside the script seems to work, just no servo motion.

//-| CNC-CW80170 Coil Winding Mechine (2024)  //
//-| Author: Michael S. Larson               //
//-| VERSION: 1.2                           //
//-| ------------------------------------- //

//- Includes for ILI9341 Capable SPI Display 
//- 2.8 inch TFT SPI Touch Screen v1.1 (2024)YTD 
#include <SPI.h>
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

//- Includes for Touch Screen Functionality
#include <XPT2046_Touchscreen.h>

//- Includes for Stepper Moters
#include <AccelStepper.h>
#include <Wire.h>

//- Define ILI9341 Pins
#define TFT_CS 28
#define TFT_RST 30
#define TFT_DC 32

//- Define Touch Pins
//- If no Interupt, comment out
#define TS_CS 34
//#define TS_IRQ

//- Define CNC Sheild Pins
// Define motor step constants (adjust based on your motor specifications)
#define STEPS_PER_REV 200
#define SCREW_PITCH 0.8

// Define stepper motor pins
#define SPINDLE_DIR_PIN 5
#define SPINDLE_STEP_PIN 2
#define BOBBIN_DIR_PIN 6
#define BOBBIN_STEP_PIN 3
#define ENABLE_PIN 8
#define LIMIT_SWITCH_PIN 9 // Pin for the limit switch

//- Initalize Graphics Display
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

//- Initalize Touch and IF TS_IRQ option
#ifdef TS_IRQ
  XPT2046_Touchscreen ts(TS_CS, TS_IRQ);
#else
  XPT2046_Touchscreen ts(TS_CS);
#endif

// Settings for Touch Screen Calibration and Functions
#define MINPRESSURE 200
#define MAXPRESSURE 2500

// Initalize the stepper motor instances
AccelStepper spindleStepper(AccelStepper::DRIVER, SPINDLE_STEP_PIN, SPINDLE_DIR_PIN);
AccelStepper bobbinStepper(AccelStepper::DRIVER, BOBBIN_STEP_PIN, BOBBIN_DIR_PIN);


// Varibles for Startup
int CycleCount = 0;
int ScreenRotation = 3;
// Button and Menu Varibles 
int16_t lastSelectedButton = -1;
int16_t currentMenuIndex = 0; // Start with menu 0
int NUM_BUTTONS; // Placeholder for the number of buttons to check
#define MainMenuNOB 7 // Buttons to check
#define KeypadNOB 14 // Buttons to check
//#define WindingNOB 2 // Buttons to check
int setPramLabel = 0; // 0 turns | 1 wire | 2 coilDiam | 3 coilWidth : Draw options in drawKeypad
// Text Input Varibles
int textCount = 0;
int currentKeyValue;
const int MAX_BUFFER_SIZE = 18;
char MyBuffer[MAX_BUFFER_SIZE];
float currentBuffer;
// Coil Paramiters Varibles
// Our IsSet is true, when clicking a set button, IsSet to flase for update values
// HaValue is flase, when a value besides 0 or 0.00, HasValue = true, see setPramitors, used for lockout check
bool turnPramIsSet = true; 
bool turnPramHasValue = true;
int turnPram = 41;
bool wireSizeIsSet = true;
bool wireSizeHasValue = true;
float wireSize = 0.989;
bool coilDiamIsSet = true;
bool coilDiamHasValue = true;
float coilDiam = 18.5;
bool coilWidthIsSet = true;
bool coilWidthHasValue = true;
float coilWidth = 40.05;
// CNC Variables
bool lockOut = false;
int bobbinSteps;
int spindleSteps;
int turnsPerLayer;
int layersPerCoil;
float layerOffset;
int totalBobbinSteps;
int totalSpindleSteps;
// Message Readout Varibles
int turnInteration = 0;
int bobbinInteration = 0;
int spindleInteration = 0;
int layerInteration = 0;

// Define the buttons function pointer
typedef void (*ButtonFunction)();

// Button Structure
struct Button {
  int16_t x; // x screen position
  int16_t y; // y screen position
  int16_t w; // buttons width
  int16_t h; // buttons height
  int16_t cxp; // Courser x Position
  int16_t cyp; // Courser y Position
  int buttonStyle; // See drawButton for style select
  int16_t textSize; // test size
  uint16_t color; // Buttons color
  uint16_t textColor; // text color
  const char* label; // buttons label
  int value;
  bool selected; // button selected [ true / false ]
  int menuIndex; // Index of the menu this button leads to
  ButtonFunction buttonFunction; // Button function pointer
};

// Declare function prototypes for button functions
void startFunction();
void resetFunction();
void homeFunction();
void GetKeyPress();
void setTurns();
void setWire();
void setCoilDiamitor();
void setcoilWidth();
void setPramitors();
void cancelPramitors();
// void pauseWinding();
// void stopWinding();

Button mainMenu[MainMenuNOB] = {
//   x,   y,   w,   h, cxp, cyp,  BS,  TS,   BUTTON COLOR,    TEXT COLOR,            LABEL, VALUE, SELECTED, MI,    FUNCTION 
  { 10,  90, 196,  40,  18, 100,   0,   3, ILI9341_YELLOW, ILI9341_WHITE,          "START",     0,    false,  0, startFunction}, // Button 1 leads to menu 1
  { 10, 140, 196,  40,  18, 150,   0,   3, ILI9341_YELLOW, ILI9341_WHITE,          "RESET",     0,    false,  0, resetFunction}, // Button 1 leads to menu 1
  { 10, 190, 196,  40,  18, 200,   0,   3, ILI9341_YELLOW, ILI9341_WHITE,           "HOME",     0,    false,  0, homeFunction}, // Button 1 leads to menu 1
  {229,  40,  92,  40, 234,  45,   1,   1,    ILI9341_RED, ILI9341_WHITE,          "TURNS",     0,    false,  1, setTurns}, // Button 1 leads to menu 1
  {229,  90,  92,  40, 234,  95,   1,   1,    ILI9341_RED, ILI9341_WHITE,           "WIRE",     0,    false,  1, setWire}, // Button 1 leads to menu 1
  {229, 140,  92,  40, 234, 145,   1,   1,    ILI9341_RED, ILI9341_WHITE, "COIL DIAMITTER",     0,    false,  1, setCoilDiamitor}, // Button 1 leads to menu 1
  {229, 190,  92,  40, 234, 195,   1,   1,    ILI9341_RED, ILI9341_WHITE,     "COIL WIDTH",     0,    false,  1, setcoilWidth} // Button 1 leads to menu 1
};

Button keypadMenu[KeypadNOB] = {
//   x,   y,   w,   h, cxp, cyp,  BS,  TS,   BUTTON COLOR,    TEXT COLOR,    LABEL, VALUE, SELECTED, MI,    FUNCTION
  {  2,   2,  70,  57,  30,  20,   0,   3,    ILI9341_RED, ILI9341_WHITE,      "7",     7,    false,  1,  GetKeyPress}, // Button 1 leads to menu 1
  { 74,   2,  70,  57, 102,  20,   0,   3,    ILI9341_RED, ILI9341_WHITE,      "8",     8,    false,  1,  GetKeyPress}, // Button 1 leads to menu 1
  {146,   2,  70,  57, 174,  20,   0,   3,    ILI9341_RED, ILI9341_WHITE,      "9",     9,    false,  1,  GetKeyPress}, // Button 1 leads to menu 1
  {  2,  61,  70,  57,  30,  79,   0,   3,    ILI9341_RED, ILI9341_WHITE,      "4",     4,    false,  1,  GetKeyPress}, // Button 1 leads to menu 1
  { 74,  61,  70,  57, 102,  79,   0,   3,    ILI9341_RED, ILI9341_WHITE,      "5",     5,    false,  1,  GetKeyPress}, // Button 1 leads to menu 1
  {146,  61,  70,  57, 174,  79,   0,   3,    ILI9341_RED, ILI9341_WHITE,      "6",     6,    false,  1,  GetKeyPress}, // Button 1 leads to menu 1
  {  2, 120,  70,  57,  30, 138,   0,   3,    ILI9341_RED, ILI9341_WHITE,      "1",     1,    false,  1,  GetKeyPress}, // Button 1 leads to menu 1
  { 74, 120,  70,  57, 102, 138,   0,   3,    ILI9341_RED, ILI9341_WHITE,      "2",     2,    false,  1,  GetKeyPress}, // Button 1 leads to menu 1
  {146, 120,  70,  57, 174, 138,   0,   3,    ILI9341_RED, ILI9341_WHITE,      "3",     3,    false,  1,  GetKeyPress}, // Button 1 leads to menu 1
  {  2, 179,  70,  57,  17, 195,   0,   3,    ILI9341_RED, ILI9341_WHITE,     "<<",    -1,    false,  1,  GetKeyPress}, // Button 1 leads to menu 1
  { 74, 179,  70,  57, 102, 195,   0,   3,    ILI9341_RED, ILI9341_WHITE,      "0",     0,    false,  1,  GetKeyPress}, // Button 1 leads to menu 1
  {146, 179,  70,  57, 174, 195,   0,   3,    ILI9341_RED, ILI9341_WHITE,      ".",    -2,    false,  1,  GetKeyPress}, // Button 1 leads to menu 1
  {229, 140,  92,  40, 243, 153,   0,   2,    ILI9341_RED, ILI9341_WHITE,    "SET",     0,    false,  0,  setPramitors}, // Button 1 leads to menu 1
  {229, 190,  92,  40, 243, 203,   0,   2,    ILI9341_RED, ILI9341_WHITE, "CANCEL",     0,    false,  0,  cancelPramitors}  // Button 1 leads to menu 1
};

// Button windingMenu[WindingNOB] = {
//   x,   y,   w,   h, cxp, cyp,  BS,  TS,   BUTTON COLOR,    TEXT COLOR,       LABEL, VALUE, SELECTED, MI,    FUNCTION
//  { 15, 170, 140,  57,  40, 188,   0,   3, ILI9341_YELLOW, ILI9341_WHITE,     "PAUSE",     0,    false,  2,  pauseWinding}, // Button 1 leads to menu 1
//  {165, 170, 140,  57, 200, 188,   0,   3,    ILI9341_RED, ILI9341_WHITE,      "STOP",     0,    false,  0,  stopWinding} // Button 1 leads to menu 1
// };

// Pointer for arrays of menu
// Used later in the checking of buttons
Button *menu;

void GetKeyPress() {
  // This function is used on the keypad from the buttons function
  // Get the value of the button that was press
  if (currentKeyValue >= 0 && currentKeyValue <= 9) {
    // If it's a numerical key (0-9)
    if (textCount < MAX_BUFFER_SIZE - 1) {
      // If the buffer isn't full, append the key value to the buffer
      MyBuffer[textCount++] = '0' + currentKeyValue;
      MyBuffer[textCount] = '\0'; // Null-terminate the string
    } else {
      Serial.print("Buffer full, value not set");
    }
    Serial.print("Buffer: ");
    Serial.println(MyBuffer);
  } else if (currentKeyValue == -1) {
    // If the user presses the backspace key (<<)
    if (textCount > 0) {
      textCount--;
      MyBuffer[textCount] = '\0'; // Null-terminate the string
    }
    Serial.print("Buffer: ");
    Serial.println(MyBuffer);
  } else if (currentKeyValue == -2) {
    // If the user presses the decimal key (.)
    if (textCount < MAX_BUFFER_SIZE - 1) {
      // Check if a decimal point is already present in the buffer
      bool decimalPresent = false;
      for (int i = 0; i < textCount; i++) {
        if (MyBuffer[i] == '.') {
          decimalPresent = true;
          break;
        }
      }

      if (!decimalPresent) {
        // If no decimal point is present, append it to the buffer
        MyBuffer[textCount++] = '.';
        MyBuffer[textCount] = '\0'; // Null-terminate the st ring
      }
    }
    Serial.print("Buffer: ");
    Serial.println(MyBuffer);
  }
  currentBuffer = atof(MyBuffer);
  Serial.println(currentBuffer);
  updateScreen();
}

void setPramitors() {
  Serial.println("setPramitors was called");
  
  if (!turnPramIsSet) {
    turnPram = atoi(MyBuffer); // Convert the buffer to float and store in turnPram
    turnPramIsSet = true;
    if (turnPram != 0) {
      mainMenu[3].color = ILI9341_GREEN;
      turnPramHasValue = true;
    }
    Serial.print("Turns: ");
    Serial.println(turnPram);
  } else if (!wireSizeIsSet) {
    wireSize = atof(MyBuffer); // Convert the buffer to float and store in wireSize
    wireSizeIsSet = true;
    if (wireSize != 0) {
      mainMenu[4].color = ILI9341_GREEN;
      wireSizeHasValue = true;
    }
    Serial.print("Wire: ");
    Serial.println(wireSize);
  } else if (!coilDiamIsSet) {
    coilDiam = atof(MyBuffer); // Convert the buffer to float and store in coilDiam
    coilDiamIsSet = true;
    if (coilDiam != 0) {
      mainMenu[5].color = ILI9341_GREEN;
      coilDiamHasValue = true;
    }
    Serial.print("Coil Diameter: ");
    Serial.println(coilDiam);
  } else if (!coilWidthIsSet) {
    coilWidth = atof(MyBuffer); // Convert the buffer to float and store in coilWidth
    coilWidthIsSet = true;
    if (coilWidth != 0) {
      mainMenu[6].color = ILI9341_GREEN;
      coilWidthHasValue = true;
    }
    Serial.print("Coil Width: ");
    Serial.println(coilWidth);
  } 
  
  // If we have a null value, reset color and HasValue
  if (turnPram == 0.00 || turnPram == 0) {
    mainMenu[3].color = ILI9341_RED;
    turnPramHasValue = false;
  } 
  if (wireSize == 0.00 || wireSize == 0) {
    mainMenu[4].color = ILI9341_RED;
    wireSizeHasValue = false;
  } 
  if (coilDiam == 0.00 || coilDiam == 0) {
    mainMenu[5].color = ILI9341_RED;
    coilDiamHasValue = false;
  } 
  if (coilWidth == 0.00 || coilWidth == 0) {
    mainMenu[6].color = ILI9341_RED;
    coilWidthHasValue = false;
  }

  // Clear the buffer after saving the value
  memset(MyBuffer, 0, MAX_BUFFER_SIZE);
  textCount = 0;
  currentBuffer = 0;
}

void updateScreen() {
  Serial.println("updateScreen was called");

  // Backfill the display
  tft.fillRect(221, 47, 98, 20, ILI9341_WHITE);
  
  // Set our what we are updating
  tft.setCursor(225, 48);
  tft.setTextSize(2);
  tft.setTextColor(ILI9341_BLACK);
  tft.print(currentBuffer);
}

void setup() {
  // Scren and Touch setting
  // Set devices outputs to high, turning there select off (High = Off / Low = On)
  pinMode(TFT_CS, OUTPUT);
  digitalWrite(TFT_CS, HIGH);

  pinMode(TS_CS, OUTPUT);
  digitalWrite(TS_CS, HIGH);

  // CNC Shield Settings
  // Set device output to low, turn the select off (High = On / Low = Off)
  // This is the only different in hardware selects
  pinMode(SPINDLE_DIR_PIN, OUTPUT);
  pinMode(SPINDLE_STEP_PIN, OUTPUT);
  pinMode(BOBBIN_DIR_PIN, OUTPUT);
  pinMode(BOBBIN_STEP_PIN, OUTPUT);
  pinMode(ENABLE_PIN, OUTPUT);
  digitalWrite(ENABLE_PIN, HIGH);

  // Begin the serial connections through USB
  Serial.begin(9600);
  Serial.println("Started!");

  // Start the Display and turn the rotation to the correct viewing angel, backfill screen
  tft.begin();  
  tft.setRotation(ScreenRotation);
  tft.fillScreen(0x0000);

  // Start the touch
  ts.begin();
  ts.setRotation(ScreenRotation);
  while (!Serial && (millis() <= 1000));

  // Set the Servo Motors
  spindleStepper.setMaxSpeed(1000);  // Adjust based on your motor specifications
  spindleStepper.setAcceleration(500);  // Adjust based on your motor specifications
  bobbinStepper.setMaxSpeed(1000);  // Adjust based on your motor specifications
  bobbinStepper.setAcceleration(500);  // Adjust based on your motor specifications

  // Set the menu and number of buttons
  NUM_BUTTONS = MainMenuNOB;
  menu = mainMenu;

  drawMenu(); // Already set to 0 for main menu
}

void loop() {
  // Call Update draw and update functions from buttons presses
  if (!lockOut) {
    // Set the menu and number of buttons to check
    // If they are already set, leave if be
    if (currentMenuIndex == 0 && NUM_BUTTONS != MainMenuNOB) {
      NUM_BUTTONS = MainMenuNOB;
      menu = mainMenu;
    } else if (currentMenuIndex == 1 && NUM_BUTTONS != KeypadNOB) {
      NUM_BUTTONS = KeypadNOB;
      menu = keypadMenu;
    } /*else if (currentMenuIndex == 2 && NUM_BUTTONS != WindingNOB) {
      NUM_BUTTONS = WindingNOB;
      menu = windingMenu;
    }*/

    // Touch Screen Buttons Checks
    // Check if we have touch
    if (ts.touched()) {
      // get the touch points and pressure
      TS_Point p = ts.getPoint();
      
      // Mapping for touch screen too display cords (Pixels)
      // This part is configured for my screen if head pins where point west
      int16_t x = map(p.x, 250, 3800, tft.width(), 0);
      int16_t y = map(p.y, 330, 3700, tft.height(), 0);

      // Serial Printout: Pressure - Touch Cords / Screen Cords
      Serial.print("Pressure = ");
      Serial.print(p.z);
      Serial.print(", X = ");
      Serial.print(p.x);
      Serial.print(", Y = ");
      Serial.print(p.y);
      Serial.println();
      Serial.print("Screen Cords: X = ");
      Serial.print(x);
      Serial.print(", Y = ");
      Serial.print(y);
      Serial.println();
      delay(30);

      // If the pressure detected is with-in range
      if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
        // Check all the buttons to see if the touch matches

        for (int i = 0; i < NUM_BUTTONS; i++) {
          if (x > menu[i].x && x < menu[i].x + menu[i].w && y > menu[i].y && y < menu[i].y + menu[i].h) {
            Serial.print("Buttons Found: ");
            Serial.println(menu[i].label);
            
            // if the menu item is not selected
            if (!menu[i].selected) {
              Serial.println("Button selected = false");
              
              // Check for the last select button
              if (lastSelectedButton != -1) {
                Serial.println("Last selected button found");
                menu[lastSelectedButton].selected = false;
                drawButton(menu[lastSelectedButton]);
              }

              menu[i].selected = true;
              lastSelectedButton = i;
              highlightButton(menu[i]);
            }
              
            // Change menu if button leads to another menu
            if (menu[i].menuIndex != currentMenuIndex && !ts.touched()) {
              // Start the button function first before changing the menu
              menu[i].buttonFunction();
              changeMenu(menu[i].menuIndex); // Menu indices are zero-based
            } else if (!ts.touched() && menu[i].buttonFunction == GetKeyPress) {
              Serial.println("Calling GetKeyPress");
              // We need to set what button value was pressed here then call its function
              currentKeyValue = menu[i].value;
              menu[i].buttonFunction();
            } else if (!ts.touched()) {
              // For any other function without special conditions
              menu[i].buttonFunction();
            }
            //delay(10);
            break; // Exit loop once a button is found
          }
          // Deselect the previously selected button if touch is detected and we are not on a button
          else if (lastSelectedButton != -1 && menu[i].selected) {
            Serial.println("Touch found but no on a button: Deselecting lastSelectedButton");
            menu[lastSelectedButton].selected = false;
            drawButton(menu[lastSelectedButton]);
            lastSelectedButton = -1;
          }        
        }
      } 
    }
    // Deselect the previously selected button if no touch is detected
    else if (lastSelectedButton != -1) {
      Serial.println("There is no touch: Deselecting lastSelectedButton");
      menu[lastSelectedButton].selected = false;
      drawButton(menu[lastSelectedButton]);
      lastSelectedButton = -1;
    }
  }
}

void drawButton(Button button) {
  Serial.print("drawButton ");
  Serial.println(button.label);
  tft.fillRect(button.x, button.y, button.w, button.h, ILI9341_BLACK);
  tft.drawRect(button.x, button.y, button.w, button.h, button.color);
  tft.setTextColor(button.textColor);
  tft.setCursor(button.cxp, button.cyp);
  tft.setTextSize(button.textSize);
  tft.print(button.label);
}

void highlightButton(Button button) {
  Serial.print("highlightButton ");
  Serial.println(button.label);
  tft.fillRect(button.x +1, button.y +1, button.w -2, button.h -2, ILI9341_DARKGREY);
  tft.setTextColor(button.textColor);
  tft.setCursor(button.cxp, button.cyp);
  tft.setTextSize(button.textSize);
  tft.print(button.label);
}

void drawMenu() {
  Serial.println("Drawing Menu");

  // Back fill the screen
  tft.fillScreen(ILI9341_BLACK);

  // overlay the information
  /*if (currentMenuIndex == 2) {
    drawWinding();
  }*/

  // draw the buttons
  // set from startup and changeMenu
  for (int i = 0; i < NUM_BUTTONS; i++) {
      drawButton(menu[i]);
  }

  // overlay the information
  if (currentMenuIndex == 0) {
    drawMainMenu();
  } else if (currentMenuIndex == 1) {
    drawKeypad();
  }
}

void changeMenu(int newMenuIndex) {
  Serial.println("Changing Menu: Reset Selected");

  // Lets change all are selected back to false for the current selected menu
  for (int i = 0; i < NUM_BUTTONS; i++) {
    menu[i].selected = false;
  }

  // very important for menu change
  // if the lastSelectedButton is not set back to -1, it will cause erros on menu change
  // due to the different number of buttons each menu has with the button draws
  lastSelectedButton = -1;
  currentMenuIndex = newMenuIndex;
  
  // Set the menu and number of buttons to check
  if (currentMenuIndex == 0) {
    NUM_BUTTONS = MainMenuNOB;
    menu = mainMenu;
  } 
  if (currentMenuIndex == 1) {
    NUM_BUTTONS = KeypadNOB;
    menu = keypadMenu;
  }
  /*if (currentMenuIndex == 2) {
    NUM_BUTTONS = WindingNOB;
    menu = windingMenu;
  }*/

  // With everything set, lets draw our menus
  drawMenu();
}

void calculateSteps() {
  // This function is one of the nost important functions on this program. It calculates the differnt
  // messurements for both our display, updates, and winding process. Please note, this is set up for 
  // Orthocyclic Linear Winding. The size of the coil will effect the function of the machine. So with
  // that said, the coil needs to be designed for the wires width (including its coating) and # of turns
  // plus half the wire size for layer offset. This should allow enough room for the next layers offset. 
  // Example Values: coilWidth = 40.05 | coilDiameter = 18.5 | wireSize = 0.989 | turnPram = 500

  // Calculate the number of turns needed for one layer of the coil
  turnsPerLayer = coilWidth / wireSize; 
  // example: 40.05 / 0.989 = 40.4954
  Serial.print("turnsPerLayer: ");
  Serial.println(turnsPerLayer);

  // Calculate the number of layers needed for the entire coil
  layersPerCoil = turnPram / turnsPerLayer;
  // example: 500 / 40.4954 = 12.3470
  Serial.print("layersPerCoil: ");
  Serial.println(layersPerCoil);

  // Calculate the offset distance the spindle needs to move for each layer offset. note that the spacing 
  // from the coils width / wire Size is 40.4954. This is roughly the radius of the wireSize (its radius).
  // This should place every wire inbetween each other for the layer offset.
  layerOffset = wireSize / 2;
  // example: 0.989 / 2 = 0.4945
  Serial.print("layerOffset: ");
  Serial.println(layerOffset);

  // Calculate steps for bobbin stepper (one full turn). This draws the wire around the bobbin / cylinder
  bobbinSteps = STEPS_PER_REV; 
  // exsmple: 200
  Serial.print("bobbinSteps: ");
  Serial.println(bobbinSteps);

  // Calculate steps for spindle stepper to move the wire size distance for the next turn. This is dependent
  // on your mechanical setup. With my mechine, I have a thread rod with a pitch 0.8 attached to the servo.
  // The threaded rod holds the wire guide. If one turn equals 200 steps (1 full rev), our spindle would 
  // move the guide 0.8 mm's per rev. We need to devide 1 rev (200) by our spindles pitch to figure out what
  // 1 mm of movement would be. This is the same for any threaded rod. With the math below, 250 steps equals 
  // 1 mm of movememt. Next we calculate the steps the spindle servo needs to move base off of our wire size. 
  // This is how many steps it would take to move our wireSize over for the next turn  
  int stepsPerMillimeter = STEPS_PER_REV / SCREW_PITCH;
  spindleSteps = round(wireSize * stepsPerMillimeter);
  // stepsPerMillimeter = 200 / 0.8 = 250 = 1mm
  // spindleSteps = 0.989 * 250 = 247.25 = rounded 247 steps
  Serial.print("stepsPerMillimeter: ");
  Serial.println(stepsPerMillimeter);
  Serial.print("spindleSteps: ");
  Serial.println(spindleSteps);

  // Calculate total steps needed for the bobbin stepper based on the total number of turns
  totalBobbinSteps = turnPram * bobbinSteps;
  Serial.print("totalBobbinSteps: ");
  Serial.println(totalBobbinSteps);

  // Calculate total steps needed for the spindle stepper based on the total number of turns
  totalSpindleSteps = turnPram * spindleSteps;
  Serial.print("totalSpindleSteps: ");
  Serial.println(totalSpindleSteps);
}

// Function to control the stepper motors for the winding process
void windCoil() {
  lockOut = true;
  digitalWrite(ENABLE_PIN, LOW);
  calculateSteps();
  drawWinding();
  bool reverse = false;

  for (int layer = 0; layer < layersPerCoil; layer++) {
    for (int turn = 0; turn < turnsPerLayer; turn++) {
      Serial.println("Cycle Check");
      turnInteration++;
      spindleInteration = spindleSteps + spindleInteration;
      bobbinInteration = bobbinSteps + bobbinInteration;

      // Move bobbin stepper for one turn
      bobbinStepper.move(bobbinSteps);
      bobbinStepper.runToPosition(); // Ensure the bobbin completes one turn

      // Move spindle stepper by wireOffset steps
      if (reverse) {
        spindleStepper.move(-spindleSteps);
      } else {
        spindleStepper.move(spindleSteps);
      }
      spindleStepper.runToPosition(); // Ensure the spindle moves to the correct position
      updateWinding();
    }
    layerInteration++;
    // Apply layer offset and reverse direction after each layer
    if (reverse) {
      spindleStepper.move(layerOffset);
    } else {
      spindleStepper.move(-layerOffset);
    }
    spindleStepper.runToPosition(); // Move spindle to the offset position
    reverse = !reverse;
  }
  turnInteration = 0;
  layerInteration = 0;
  spindleInteration = 0;
  bobbinInteration = 0;
  digitalWrite(ENABLE_PIN, HIGH);
  lockOut = false;
  changeMenu(0);
}

void startFunction() {
  Serial.println("Start Function was called");
  if (turnPramHasValue && wireSizeHasValue && coilDiamHasValue && coilWidthHasValue) {
    Serial.println("HasValue Check Passed: Starting Winding");
    //changeMenu(2);
    windCoil();
  } else {
    Serial.println("HasValue Check Failed: Display Error Message");
    drawErrorMessage();

    // Lets change all are selected back to false for the current selected menu
    // I dont think this is needed but im not sure as of now - more checking is needed
    for (int i = 0; i < NUM_BUTTONS; i++) {
      menu[i].selected = false;
    }
    lastSelectedButton = -1;
    delay(4000);
    drawMenu();
  }
}

void resetFunction() {
  Serial.println("Reset Function was called");
  turnPram = 0;
  wireSize = 0;
  coilDiam = 0;
  coilWidth = 0;
  mainMenu[3].color = ILI9341_RED;
  mainMenu[4].color = ILI9341_RED;
  mainMenu[5].color = ILI9341_RED;
  mainMenu[6].color = ILI9341_RED;
  turnPramIsSet = true;
  wireSizeIsSet = true;
  coilDiamIsSet = true;
  coilWidthIsSet = true;
  turnPramHasValue = false;
  wireSizeHasValue = false;
  coilDiamHasValue = false;
  coilWidthHasValue = false;
  for (int i = 0; i < NUM_BUTTONS; i++) {
    menu[i].selected = false;
  }
  drawMenu();
}

void homeFunction() {
  Serial.println("Home Function was called");
  spindleStepper.setMaxSpeed(500); // Reduce speed for homing
  spindleStepper.setAcceleration(100);

  while (digitalRead(LIMIT_SWITCH_PIN) == HIGH) {
    spindleStepper.moveTo(spindleStepper.currentPosition() - 1); // Move spindle stepper towards home
    spindleStepper.run();
  }
  spindleStepper.moveTo(spindleStepper.currentPosition() + 1); // Move spindle stepper away from home
  spindleStepper.setCurrentPosition(0); // Set home position to zero
}

void cancelPramitors() {
  Serial.println("cancelPramitors was called: MyBuffer Reset, textCount = 0");
  
  // Clear the buffer after saving the value
  memset(MyBuffer, 0, MAX_BUFFER_SIZE);
  textCount = 0;
  currentBuffer = 0;
}

void setTurns() {
  Serial.println("setTurns was called: PramIsSet = False");
  turnPramIsSet = false;
  setPramLabel = 0;
}

void setWire() {
  Serial.println("setTurns was called: PramIsSet = False");
  wireSizeIsSet = false;
  setPramLabel = 1;
}

void setCoilDiamitor() {
  Serial.println("setTurns was called: PramIsSet = False");
  coilDiamIsSet = false;
  setPramLabel = 2;
}

void setcoilWidth() {
  Serial.println("setTurns was called: PramIsSet = False");
  coilWidthIsSet = false;
  setPramLabel = 3;
}

/*void pauseWinding() {
  Serial.println("pauseWinding was called");
}

void stopWinding() {
  Serial.println("stopWinding was called");
}*/

void drawMainMenu() {
  // Rev Loop
  // turn into function later..
  tft.fillRect(10, 65, 209, 7, 0x0000);
  tft.setCursor(10, 65);
  tft.setTextSize(1);
  tft.setTextColor(0xbbbb);
  tft.print(CycleCount);

  // Mechine info and Main Buttons Draw
  tft.setCursor(10, 20);
  tft.setTextSize(3);
  tft.setTextColor(0xbbbb);
  tft.println("CNC-CW80170");
  tft.setCursor(10, 45);
  tft.setTextSize(1);
  tft.println("Computer Numerical Controled Unit");
  tft.setCursor(10, 55);
  tft.println("Coil Winding Mechine        v1.00");

  // Line Draw for other half of the screen
  tft.drawLine(219, 0, 219, 240, 0xffff);
  tft.drawLine(219, 30, 320, 30, 0xffff);

  // Coil Pramitors Display
  tft.setCursor(229, 5);
  tft.setTextSize(1);
  tft.setTextColor(0xffff);
  tft.println("COIL PRAMITORS");
  // Ready Status of Coil Pramitors
  tft.setCursor(229, 16);
  tft.setTextSize(1);
  if (turnPram != 0 && wireSize != 0 && coilDiam != 0 && coilWidth != 0) {
    tft.setTextColor(ILI9341_GREEN);
    tft.println("READY!");
  } else {
    tft.setTextColor(0xb101);
    tft.println("NOT READY!");
  }

  // Turns Display
  tft.setCursor(234, 58);
  tft.setTextSize(2);
  if (turnPram == 0) {
    tft.setTextColor(0xb101);
    tft.println("NOT SET");
  } else {
    tft.setTextColor(ILI9341_WHITE);
    tft.println(turnPram);
  }

  // Wire Dispaly
  tft.setCursor(234, 108);
  tft.setTextSize(2);
  if (wireSize == 0) {
    tft.setTextColor(0xb101);
    tft.println("NOT SET");
  } else {
    tft.setTextColor(ILI9341_WHITE);
    tft.println(wireSize);
  }

  // Coil Diamiter Display
  tft.setCursor(234, 158);
  tft.setTextSize(2);
  if (coilDiam == 0) {
    tft.setTextColor(0xb101);
    tft.println("NOT SET");
  } else {
    tft.setTextColor(ILI9341_WHITE);
    tft.println(coilDiam);
  }

  // Coil Width Display
  tft.setCursor(234, 208);
  tft.setTextSize(2);
  if (coilWidth == 0) {
    tft.setTextColor(0xb101);
    tft.println("NOT SET");
  } else {
    tft.setTextColor(ILI9341_WHITE);
    tft.println(coilWidth);
  }
}

void drawKeypad() {
  // Line Draw for other half of the screen
  tft.fillRect(219, 0, 100, 32, 0xb101);
  tft.drawLine(219, 0, 219, 240, 0xffff);

  // Coil Pramitors Display
  tft.setCursor(229, 5);
  tft.setTextSize(1);
  tft.setTextColor(0xffff);
  tft.println("COIL PRAMITORS");

  // Ready Status of Coil Pramitors
  tft.setCursor(229, 16);
  tft.setTextSize(1);
  tft.setTextColor(0xFFFF);
  tft.println("KEYPAD SETTINGS");

  // Display setting window
  tft.fillRect(219, 30, 102, 40, ILI9341_WHITE);
  tft.drawRect(220, 31, 100, 38, ILI9341_DARKGREY);
  tft.setCursor(225, 36);
  tft.setTextSize(1);
  tft.setTextColor(ILI9341_BLACK);
  if (setPramLabel == 0) {
    tft.println("Turns");
  } else if (setPramLabel == 1) {
    tft.println("Wire Size");
  } else if (setPramLabel == 2) {
    tft.println("Coil Diamitor");
  } else if (setPramLabel == 3) {
    tft.println("Coil Width");
  }

  tft.setCursor(225, 48);
  tft.setTextSize(2);
  tft.print(currentBuffer);
}

void drawWinding() {
  Serial.println("Drawing Winding Screen");

  tft.fillScreen(ILI9341_BLACK);
  tft.drawRect( 2, 2, 316, 236, ILI9341_GREEN);

  // WINDING COIL
  tft.setCursor(18, 25);
  tft.setTextSize(3);
  tft.setTextColor(ILI9341_GREEN);
  tft.print("! WINDING COIL !");

  tft.setTextSize(1);
  tft.setTextColor(ILI9341_WHITE);

  // Turns
  tft.drawRect(15, 70, 140, 40, ILI9341_GREEN);
  tft.drawRect(20, 85, 130, 20, ILI9341_GREEN);
  tft.setCursor(19, 74);
  tft.print("Turns Set");
  tft.setCursor(25, 92);
  tft.print(turnInteration);
  tft.setCursor(80, 92);
  tft.print("/");
  tft.setCursor(90, 92);
  tft.print(turnPram);

  // Spindle Steps Total
  tft.drawRect(165, 70, 140, 40, ILI9341_GREEN);
  tft.drawRect(170, 85, 130, 20, ILI9341_GREEN);
  tft.setCursor(169, 74);
  tft.print("Spindle Steps");
  tft.setCursor(175, 92);
  tft.print(spindleInteration);
  tft.setCursor(230, 92);
  tft.print("/");
  tft.setCursor(240, 92);
  tft.print(totalSpindleSteps);

  // Layers 
  tft.drawRect(15, 120, 140, 40, ILI9341_GREEN);
  tft.drawRect(20, 135, 130, 20, ILI9341_GREEN);
  tft.setCursor(19, 124);
  tft.print("Layers Total");
  tft.setCursor(25, 142);
  tft.print(layerInteration);
  tft.setCursor(80, 142);
  tft.print("/");
  tft.setCursor(90, 142);
  tft.print(layersPerCoil);

  // Bobbin Step Total
  tft.drawRect(165, 120, 140, 40, ILI9341_GREEN);
  tft.drawRect(170, 135, 130, 20, ILI9341_GREEN);
  tft.setCursor(169, 124);
  tft.print("Bobbin Steps");
  tft.setCursor(175, 142);
  tft.print(bobbinInteration);
  tft.setCursor(230, 142);
  tft.print("/");
  tft.setCursor(240, 142);
  tft.print(totalBobbinSteps);
}

void updateWinding() {
  tft.fillRect( 21, 86, 128, 18, ILI9341_BLACK);
  tft.fillRect(171, 86, 128, 18, ILI9341_BLACK);
  tft.fillRect( 21,136, 128, 18, ILI9341_BLACK);
  tft.fillRect(171,136, 128, 18, ILI9341_BLACK);

  // Turns
  tft.setCursor(25, 92);
  tft.print(turnInteration);
  tft.setCursor(80, 92);
  tft.print("/");
  tft.setCursor(90, 92);
  tft.print(turnPram);

  // Spindle Steps Total
  tft.setCursor(175, 92);
  tft.print(spindleInteration);
  tft.setCursor(230, 92);
  tft.print("/");
  tft.setCursor(240, 92);
  tft.print(totalSpindleSteps);
 
  // Layers 
  tft.setCursor(25, 142);
  tft.print(layerInteration);
  tft.setCursor(80, 142);
  tft.print("/");
  tft.setCursor(90, 142);
  tft.print(layersPerCoil);

  // Bobbin Step Total
  tft.setCursor(175, 142);
  tft.print(bobbinInteration);
  tft.setCursor(230, 142);
  tft.print("/");
  tft.setCursor(240, 142);
  tft.print(totalBobbinSteps);
}

void drawErrorMessage() {
  tft.fillScreen(ILI9341_BLACK);
  tft.drawRect(20, 20, 280, 100, ILI9341_RED);
  tft.setCursor(60, 40);
  tft.setTextColor(ILI9341_RED);
  tft.setTextSize(3);
  tft.print("!! ERROR !!");
  tft.setCursor(40, 80);
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(1);
  tft.println("Please set ALL Pramitors first!");
}
1 Like

Don't throw it, all will be well! Here is a page from Pololu about configuring the A4988 (and a lot more information). Have a thorough read...

Using a regular V3 / V4 CNC shield on a mega can be full of surprises.
They are designed to be used with the UNO.
This means the pins are usually different from what you would expect.
My suggestion would be to buy a UNO, and if you got the sketch from online then revert to that.
There are lots of coil winding projects you can probably adapt quickly to your usage.

Bob.

Never intended too. This project has been well worth the effort. I did check out the article you sent. Most of the information in there I read before. But it did get me thinking about amps and what it takes to run the Nema 17. They take 1.5 amps to run. The driver is rated for 2 amps with cooling, 1 without. After diving a little more, the NEMA 17 is recommended to run with the DRV2588 rated up to 2 amps without cooling and 3 with. May be wrong about this as I am not referencing any documentation right now. I've ordered these now and should be here tomorrow for testing.

Ballscrewbob2, thanks for the reply. I had a problem with what you where talking about but with a different issue. The 3.5 tft SPI touch screens (touch) was not working. Come to find out, the pin out on the uno vs mega SPI pins are a bit different. Hardware was a concern. The XPT(SOMETHING) library is ment to work of off dedicated SPI lines. The adafruit graphics library will allow you to define other pins for your SPI but the XPT only uses the default SPI Lines. They don't cover this well in the documentation.

The CNC shield for the uno covers these SPI but gives you the pins on the shield board. Moreover, the mega also supply's you with three headers for the SPI. Long story short, use your dedicated lines for SPI and the XPT Library. When channeling with a script to be used on different pins slows the chipset down for the SPI. More processing then needed.

You are right about the CNC shield. However, I'm not using GRBL. I've read that the uno shield when used with a mega will not work for GRBL. You need a the ramps 1.4 shield for this. Problem is, this covers up all the mega.

I'm going to take a look at the pinout in more detail as you suggested and do a comparison. Its something to check and I'd rather be safe then sorry. With that said, I'm using the accelstepper library and have seen others use the same shield on the mega without GRBL. There steppers ran just fine.

I plan to set up my uno with one of these tomorrow if time allows. I'll update when I get done testing. Thank you all for your pointers. Any other information you can point me to is a step in the right direction. And never give up!

So I went ahead and pulled out my uno and connected the CNC shield to it. Below are the images. Sorry, only my phone as internet access ATM so the best I could do is give a snapshot of the code. When testing, nothing happens. This is a new CNC shield that I pulled out with the old drivers.

I've checked the vref at .78 for the 1.5 amps per phase. Still using the a4988 driver. Vmot is at 23.4 volts. I turned the power supply down at after reading that the driver could only handle up to 24V. It was at 24.3. I don't think that the driver would be burnt out with the extra .3 volts but alas, im not sure.

I do have a burnt driver and it only reads .003v when plugged in for the vref.

There is a jumper on enable to ground. No jumpers underneath the driver, full step. I have tried this without the enable jumper on and still nothing.

I'm at a loss. So question is, what else can I check? Do I have a code error? Still waiting on my other drivers to come in.

So I wanted to give everyone an update. I am considering this closed as the steppers are now working. It took testing out all the PWM lines all the way up to the driver itself. All of which was spot on sending the voltage / data. From the data sheets, I went ahead and check the steppers and its wiring.

Data Sheet for the STEPPERS

The steppers have 6 pins on them. Example: ( 1 - 2 - 3 - 4 - 5 - 6 ). They way they were hocked up from the manufacturer was as one the data sheet. Test showed the coil 1 was instead 1 and 4 and coil 2 was on 3 and 6.

A bit of pin rearranging with the DuPont pins and up they ran. I have a bit more programing to do but everything is running at this point. Just want to thank you guys for giving me areas to check out on the CNC Shield and stepper motors. The DRV are running hot but its nothing they can't handle. Very happy with the outcome.

1 Like

When posting errors beware that screenshots are often useless when taken from a camera.
Better to take a proper screenshot using the computers built in function's.
Better still is to copy the text out and paste that back in here. Almost all programs allow you to do that.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.