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!");
}