Project in progress
UMT's Coil Winder

UMT's Coil Winder © CC BY

There are 20 predefined wire sizes to choose from and/or one can also enter in custom sizes including their bobbin size.

  • 4,104 views
  • 2 comments
  • 14 respects

Components and supplies

Ard nano
Arduino Nano R3
Can also use the UNO
×1
TB6600 Single Axis Stepper Motor Driver Controller
×2
Nema 17 200 step 1.8 degree stepper motor
×2
Adafruit industries ada260 image 90px
USB-A to Mini-USB Cable
×1
10-32 rod
×1
10-32 coupler nut
×1

Necessary tools and machines

Apps and online services

About this project

I made this project to save money on buying custom made coils. I needed a machine that could make several different size coils using different bobbin sizes and different wire sizes. I also needed to save the specs of each coil so the logical choice was to use a PC and a Nano or Uno 3 through a USB connection.

This project uses the Arduino Nano but, one can also use a Uno and there are 2 parts of code used, the first is a Windows program written in C# that does the settings, commands, and the calculations. The second part is the Arduino code.This frees up a lot of memory use on the Arduino Nano. Well below what I was expecting, leaving lots of room for additional features.

"Sketch uses 21250 bytes (69%) of program storage space. Maximum is 30720 bytes. Global variables use 1187 bytes (57%) of dynamic memory, leaving 861 bytes for local variables. Maximum is 2048 bytes."

There are 20 predefined wire sizes to choose from and/or one can also enter in custom sizes. One can also enter in their bobbin sizes, the machine I'm making has a max of 6" long and about 4" in diameter. One can also enter in the winding speed and acceleration but, not for the carriage, it uses a 10-32 rod so acceleration is not a concern. I also have added in travel limit switches along with max and min manual limits manually set if one desires. You can also cycle the carriage to find the limit switches. I tried using Nema 17 48 step motors but, they were not accurate so it is best to use 200 step revolution motors. I also used 2 TB6600 motor controllers but, any 2 wire (direction and step) controller should work. The carriage motor drives a 10/32(TPI) threaded rod and at 6400 pulses per rev gives a resolution of 0.0000048828".

The main features of the Arduino code include things like redundant code for safety, simplified code, and lots of comments. The code is also written using different techniques so it makes for a good learning experience.

Code

UMT_COIL_WINDER_1.0Arduino
Arduino sketch
// Version 1.0.0 ALPHA - May 15 2020 - UniMatrix Technologies Coil Winder - rrichter@unimatrixtech.com. 
// Please keep in mind that I'm quite busy and may take time before I answer my emails.
// Multi Size Wire Coil Winder
// NOT TESTED ON ACTUAL MACHINE - JUST THE MOTORS HAVE BEEN TESTED ********************************************
// This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

// This is the Arduino side of the Coil Winder Project written by Ray Richter of Unimatrix Technologies
// The Widows side was written also by Ray Richter in C#.
// This Arduino code is ment to be used with 2 TB6600 stepper controlers and 2 Nema 17 stepper motors.
// The winder motor is a 1:1 ratio but can have up to 6400 steps per revolution or 0.05625 degrees of rotation per pulse.
// The carriage motor drives a 10/32(TPI) threaded rod and at 6400 pulses per rev gives a resolution of 0.0000048828".
// at 200 pulses per rev (the lowest step count) it gives a resolution of 0.00015625".

//If using metric - example:
//Threaded rod's pitch = 2 mm. This means that one revolution will move the nut 2 mm.
//Default stepping = 400 step/revolution.
// 400 step = 1 revolution = 8 mm linear motion. (4 start 2 mm pitch screw)
// 1 cm = 10 mm =>> 10/8 * 400 = 4000/8 = 500 steps are needed to move the nut by 1 cm.

#include <AccelStepper.h>
#include <MultiStepper.h>
#include <stdio.h> // for function sprintf
#include <EEPROM.h>

// Size of the incoming serial char array **** NOT OPTIMIZED ****
const byte    numChars = 100;

// temporary array for use by strtok() function
char tempChars[numChars];        

// variables to hold the parsed data
char receivedCommand[numChars] = {0};

// SET STEPPER TYPE and pins
AccelStepper winder(AccelStepper::DRIVER, 4, 5);;// pulses Digital D4 (CLK), direction Digital D5 (DIR)  1 = AccelStepper::DRIVER 2 pin setup for the TB6600 and similar
AccelStepper carriage(AccelStepper::DRIVER, 8, 9);; // pulses Digital D8 (CLK), direction Digital D9 (DIR) 1 = AccelStepper::DRIVER 2 pin setup for the TB6600 and similar

//User-defined values
// Variables used gobaly
bool          BOLcarLeft = false;         // Allow deny movig the carriage left
bool          BOLcarRight = false;        // Allow deny movig the carriage right
unsigned long carMax;                     // SETS Max carriage steps to the right
short         carMin = 0;                 // SETS Max carriage steps to the left
long          carTempPos = 1;             // Temp variable for the carriage position
bool          Coil_Build = false;         // Allow/deny coil building
unsigned long curPosition_C;              // The current carriage position
unsigned long curPosition_W = 0;          // The current winder position
unsigned long Home_Position = 0;          // The current carriage position BEFORE SETTING the HOME position
int           inTempPos = 0;              // Temp variable for the carriage position
unsigned int  LayerCount = 0;             // Count of the number of layers made
unsigned long limSwRight_Pos = 0;         // Limit Switch Right Steps Position
unsigned long limSwLeft_Pos = 0;          // Limit Switch Left Steps Position
int           limSwtLeft = 11;            // Pin number of the Left Limit Switch
int           limSwtRight = 12;           // Pin number of the Right Limit Switch
bool          newData = false;            // Whether or not there is new data from serial
long          PulsesPerLayer_Winder = 0;  // Pulses/Steps Per Layer Winder
char          receivedChars[numChars];    // The received Characters Array
long          receivedSteps = 0;          // Number of steps
long          receivedSpeed = 0;          // Speed or Steps/second
long          receivedAcceleration = 0;   // Accel Rate Steps/second^2
bool          runallowed = false;         // runallowed flag
long          StepCount = 0;              // Count Winder steps for the ratio
int           winder_direction = 1;       // (= 1: positive direction), (= -1: negative direction) used with radBtnDir
unsigned int  WindCount = 0;              // Used for the Windings per layer counter
long          windings_x = 0;             // The number of total winder steps for a given coil
long          WindCountTotal = 0;         // Keeps track of the total windings made


//SETTINGS - These are sent once to set the coil specs ------------------------------------------------------------------------------------------------
//String unicodeString = StartS + Sts + "," + strPPR_WindingM + "," + dblPPR_C + "," + PPWind_C + "," + WPLayer + "," + STEP_RATIO + "," + PPLayer_C + "," + Speed + "," + Accel + "," + radBtnDir + "," + PPI + "," + EndS;
// or                     <   S or C or t  ,      800            ,    800         ,      143       ,       218     ,       6          ,     31174       ,     650     ,     400     ,    CW or CCW    ,    6400   ,     >
// In order of transmission.
String  inType = "";       // Type of input
int     PPR_WindingM = 0;  // Winder Pulses per rev
int     PPR_C = 0;         // Carriage Pulses Per rev
float   PPWind_C = 0;      // Carriage Pulses Per Winding
float   WPLayer = 0;       // WINDINGS PER LAYER
float   STEP_RATIO = 0;    // Winder to Carriage stepper ratio
float   PPLayer_C = 0;     // Carriage steps per layer
int     Speed = 0;         // Speed Motors
int     Accel = 0;         // Acceleration
String  radBtnDir = "";    // Direction
float   PPI;               //PULSEs PER INCH
long    NWnum = 0;         //Number of windings
int     CalLayers = 0;     //Number of layers

//-------------------------------------------------------------------------
//COMMANDS - These can be sent anytime INDIVIDUALLY SENT!
//Winder Motor Enable, Carriage Motor  Enable, Left, Right, Pause, Continue, Wind_1_rev, Set_home, Start, Stop, Terminate/Clear, Status of positions
// Inorder of Received
int Lft;    // Jog/move carriage Left until pause, stop, limit switch, or set home
int Rit;    // Jog/move carriage Rightt until pause, stop, limit switch, or set home
int Pas;    // Pause
int Con;    // Continue
int W1r;    // Wind_1_revolution
int Sth;    // Set_home position, start of coil
int Str;    // Start the build
int Stp;    // Stop
int Clr;    // Terminate/Clear zero-out everything but carriage position
int Sts;    // Status of positions

//-------------------------------------------------------------------------------------
// STATUS / INDIACATORS - Sent when needed back to the computer(PC)
//indOUT, WME, CME, LED_left, LED_right, LED_paused, LED_H_set, W_PULSE, C_PULSE, WOWINDING, WOLAYER
//eg. I,100111,######,###  this what is sent to PC
// In order of transmission.
String indOUT = "I";      // Indiacator data sent to the PC
String STSout = "S";      // Status data sent to the PC 
String WME = "0";         // Winder Motor Enable
String CME = "0";         // Carriage Motor Enable
String LED_left = "0";    // The LED indiacators are either a "0" or a "1" and sent to the PC
String LED_right = "0";   //
String LED_paused = "0";  //
String LED_H_set = "0";   // Set home LED, sent to the PC
String W_PULSE = "0";     // Winder pulse count
String C_PULSE = "0";     // Carriage pulse count
char   WOWINDING[10];     // Character array for Workin On Winding count
char   WOLAYER[5];        // Character array for Workin On Layer count

//========================================================================================================================
void setup()
{
// EEPROM Locations and values:
// '0' position of Winder
// '4' position of Carriage
// '8' calculated value of carMax
// '12' Home_Position or start of the bobbin
// '16' limSwRight_Pos
// '20' limSwLeft_Pos
// '24'  NWnum - Number of total windings

// initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);             // Just for fun
  pinMode(limSwtLeft, INPUT_PULLUP);        // PIN D11 USING INTERNAL PULL-UPS
  pinMode(limSwtRight, INPUT_PULLUP);       // PIN D12 USING INTERNAL PULL-UPS
  
  winder.setEnablePin(6);                   // D6 ENABLE WINDER
  carriage.setEnablePin(10);                // D10 ENABLE CARRIAGE
  
  winder.setMaxSpeed(5000);                 //SPEED = Steps / second ***DEFAULT*** JUST ENCASE
  winder.setAcceleration(650);              //ACCELERATION = Steps /(second)^2 ***DEFAULT*** JUST ENCASE
  winder.disableOutputs();                  //disable outputs

  carriage.setMaxSpeed(5000);               //SPEED = Steps / second ***DEFAULT*** JUST ENCASE
  carriage.setAcceleration(650);            //ACCELERATION = Steps /(second)^2 ***DEFAULT*** JUST ENCASE
  carriage.disableOutputs();                //disable outputs
  unsigned int   minWidth = 20;
  winder.setMinPulseWidth(minWidth);        // self explanitory
  carriage.setMinPulseWidth(minWidth);      // self explanitory
  EEPROM.get(0, curPosition_W);             // Get stored winder Position
  winder.setCurrentPosition(curPosition_W); // Set winder Position
  delay(20);                                // Give EEPROM time to do it's job
  EEPROM.get(4, curPosition_C);               // Get stored carriage Position
  carriage.setCurrentPosition(curPosition_C); // Set carriage Position
  delay(20);
  EEPROM.get(8, carMax);                      // Get stored carMax Position
  delay(20);
  EEPROM.get(12, Home_Position);
  delay(20);
  EEPROM.get(16, limSwRight_Pos);
  delay(20);
  EEPROM.get(20, limSwLeft_Pos);
  delay(20);
limSwRight_Pos = 179200;  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  TO BE REMOVED ONCE THE WINDER STAND IS BUILT
limSwLeft_Pos = 0;  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  TO BE REMOVED ONCE THE WINDER STAND IS BUILT
  EEPROM.get(24, NWnum);
  delay(20);
  Serial.begin(115200);
  while (!Serial)
  {
    ; // wait for serial port to connect. Needed for native USB port only
   
  }
}

//  MAIN PROGRAM LOOP =======================================================================================================
void loop() 
{
// Check for new serial coms
    checkSerial();

// this temporary copy is necessary to protect the original data
// because strtok() replaces the commas with \0    
    if (newData == true)
    {
        strcpy(tempChars, receivedChars);
        parseData();
        newData = false;
    }
//function to handle the motor    
    RunTheMotor();
}

//CHECKS to see if anything is in the receive buffer  =======================================================================================================
void checkSerial() 
  {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

// While the serial port is available and no work is being done
    while (Serial.available() > 0 && newData == false) // 
    {
// Read the serial buffer
        rc = Serial.read();
        if (recvInProgress == true) 
        {
// Not at the end of the message
            if (rc != endMarker) 
            {
// Store characters in the array
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) 
                {
                    ndx = numChars - 1;
                }
            }
            else 
            {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }
        else if (rc == startMarker) 
        {
            recvInProgress = true;
        }
    }
}

//PARSE RECEIVED DATA BY GROUP  ====================================================================================================
void parseData() 
{
// split the data into its parts
    
    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(tempChars,",");      // get the first part - the string
    strcpy(receivedCommand, strtokIndx); // copy it to message
    inType = receivedCommand;         //char to string
       
    if(inType == "S")   // SETTINGS GROUP
    {
     Parse_Type_S();    // Go to the parse settings function
     newData = false;   // Work is done
     return;            // Go back to the calling function
    }

    if(inType == "C")   // COMMANDS GROUP
    {
      Parse_Type_C();   // Go to the parse commands function
      newData = false;  // Work is done
      return;           // Go back to the calling function
    }
    
   if(inType == "t")    // COM TEST reply
    {      
      Serial.println("CONNECTION IS GOOD");
      newData = false;
      return;
    }
}

// splits the SETTINGS into its parts ===============================================================================================================================
void Parse_Type_S()
{
// this is used by strtok() as an index  
    char * strtokIndx; 
      strtokIndx = strtok(NULL, ",");   // this continues where the previous call left off

// Winder Pulses per rev      
      PPR_WindingM = atoi(strtokIndx);  // atoi convert this part to an integer

// Carriage Pulses Per rev
      strtokIndx = strtok(NULL, ",");
      PPR_C = atoi(strtokIndx);         // atoi convert this part to an integer

// Carriage Pulses Per Winding
      strtokIndx = strtok(NULL, ",");
      PPWind_C = atof(strtokIndx);     // atof convert this part to a float

// WINDINGS PER LAYER
      strtokIndx = strtok(NULL, ",");
      WPLayer = atof(strtokIndx);      // atof convert this part to a float

// WINDER TO CARRIAGE RATIO
      strtokIndx = strtok(NULL, ",");
      STEP_RATIO = atof(strtokIndx);   // atof convert this part to a float

// Carriage steps(Pulses) per layer
      strtokIndx = strtok(NULL, ",");
      PPLayer_C = atof(strtokIndx);   // atof convert this part to a float
      
//Motor speed
      strtokIndx = strtok(NULL, ",");
      Speed = atoi(strtokIndx);         // atoi convert this part to an integer
      winder.setMaxSpeed(Speed);        //set speed
      carriage.setMaxSpeed(Speed);      //set speed
      
//Motor Acceleration Rate
      strtokIndx = strtok(NULL, ",");
      Accel = atoi(strtokIndx);         // atoi convert this part to an integer
      winder.setAcceleration(Accel);    //update the value of the variable
      carriage.setAcceleration(Accel);  //update the value of the variable
      
//Direction Control for the coil Winder
      strtokIndx = strtok(NULL, ",");
      radBtnDir = (strtokIndx);         // convert this part to a string
      if (radBtnDir == "0")
      {
        winder_direction = -1;          // Move winder CCW
      }
      if (radBtnDir == "1") 
      {
        winder_direction = 1;           // Move winder CW
      }

// Carriage Pulse Per Inch - USED to set the max width encase of limit switch failure >> Hopefully
      strtokIndx = strtok(NULL, ",");
      PPI = atof(strtokIndx);
      carMax = 6 * PPI;                 // Set carMax for a 7" inch long winder shaft or the useful work area, this allows for 1" space for the limit switches
      EEPROM.put(8, carMax);            // Put or store the carMax Position
      delay(20);    
      newData = false;

// Number of WINDINGS
      strtokIndx = strtok(NULL, ",");
      NWnum = atol(strtokIndx);         // atol convert this part to a long
      EEPROM.put(24, NWnum);            // Put or store the Total Number of Windings (NWnum)
      delay(20);
      newData = false;

// Number of LAYERS
      strtokIndx = strtok(NULL, ",");
      CalLayers = atoi(strtokIndx);     // atoi convert this part to an integer
      EEPROM.put(28, CalLayers);        // Put or store the Total number of Calculated Layers (CalLayers)
      delay(20);
      newData = false;
      return;
}
// PARSE THE RECEIVED COMMANDS  ===================================================================================================================================
void Parse_Type_C()
{
// split the COMMANDS into its parts
      char * strtokIndx;                              // this is used by strtok() as an index
      strtokIndx = strtok(NULL, ",");                 // this continues where the previous call left off
      strcpy(receivedCommand, strtokIndx);            // Split the bytes into an indexed array using the "," seperator

//LEFT JOG SETUP - move carriage Left until pause, stop, Limit Switches, or set home
      if(strcmp(receivedCommand, "Lft") == 0)
        {
          winder.disableOutputs();                    // disable winder
          carriage.enableOutputs();                   // disable carriage
          EEPROM.get(4, curPosition_C);               // Get stored carriage Position
          carriage.setCurrentPosition(curPosition_C); // Set the carriage Current Position to curPosition_C value
          carriage.moveTo(-carMin);                   // Move carriage to the negative/CCW rotation towards 0/carMin
          carriage.setMaxSpeed(Speed);
          carriage.setAcceleration(Accel);  //5000          
          
// Allow the carriage to move left      ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ADD IN THE LIMIT SWITCH
          runallowed = true;
          BOLcarLeft = true;
          WME = "0";
          CME = "1";
          LED_left = "1";
          LED_right = "0";
          LED_paused = "0";
          LED_H_set = "0";          
          Send_Status();    // Send the Status values to the PC **** Send_Status() is at the bottom of this code ****
          Send_Progess();    // Send the Progess values to the PC **** Send_Progess() is at the bottom of this code ****
          newData = false;

// Carriage is all the way LEFT - STOP IT
          if (curPosition_C <= 0)
            {
              carriage.disableOutputs();
              Serial.print("<= 0 carMin - Carriage is all the way LEFT");
              Serial.println(carMax);
              delay(50);
              carriage.setCurrentPosition(0);
              curPosition_C = carriage.currentPosition();
              EEPROM.put(4, curPosition_C);
              delay(20);
              CME = "0";
              LED_left = "0";
              Send_Status();
              
      // THE USB PORT NEEDS A BIT OF TIME TO TX THE DATA
              delay(20);
              Send_Progess();
              delay(20);
              BOLcarLeft = false;
              newData = false;
              return; // Return to main loop
            }
          else
            {
              return; // Return to main loop and allow the Carriage to move LEFT
            }
          return; // Return to main loop if we are here by mistake
       }

//RIGHT JOG SETUP - move carriage Right until pause, stop, Limit Switches, or set home
      if(strcmp(receivedCommand, "Rit") == 0)
        {
          winder.disableOutputs();
          carriage.enableOutputs();
          EEPROM.get(4, curPosition_C);
          carriage.setCurrentPosition(curPosition_C);
          carriage.moveTo(carMax);
          carriage.setMaxSpeed(Speed);
          carriage.setAcceleration(5000);  //Accel
          
// Allow the carriage to move RIGHT      ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ADD IN THE LIMIT SWITCH          
          runallowed = true;
          WME = "0";
          CME = "1";
          LED_left = "0";
          LED_right = "1";
          LED_paused = "0";
          LED_H_set = "0";          
          Send_Status();
          Send_Progess();
          BOLcarLeft = false;
          BOLcarRight = true;
          newData = false;
          runallowed == true;

// Carriage is all the way RIGHT - STOP IT          
          if (carriage.currentPosition() >= carMax)
          {
            carriage.disableOutputs();
            Serial.println("Carriage is all the way RIGHT");
            delay(20);
            curPosition_C = carriage.currentPosition();
            EEPROM.put(4, curPosition_C);
            delay(20);
            CME = "0";
            LED_right = "0";
            Send_Status();
            delay(20);
            Send_Progess();
            delay(20);
            newData = false;
            return;
          }
          else
            {
              return;
            }
          return;
        }

// Pause both motors
      if(strcmp(receivedCommand, "Pas") == 0)
        {
    // Disable the motors
    // Store there positions just encase we decide to cancel the build
          winder.disableOutputs(); //disable outputs
          carriage.disableOutputs(); //disable outputs
          EEPROM.put(0, curPosition_W);
          delay(20);
          curPosition_C = carriage.currentPosition();
          EEPROM.put(4, curPosition_C);
          delay(20);
          curPosition_W = winder.currentPosition();
          LED_paused = "1";
          Send_Status();
          delay(20);
          Send_Progess();
          delay(20);
          newData = false;
          return;
        }

// Continue - let the Motors conitue
      if(strcmp(receivedCommand, "Con") == 0)
        {
          winder.enableOutputs();
          carriage.enableOutputs();
          LED_paused = "0";
          Send_Status();
          delay(20);
          Send_Progess();
          delay(20);
          newData = false;
          return;
        }

// Wind 1 Revolution for 2 reasons, 1 last chance to align before buildig the coil, 2 tightens the wire on to the bobbin
      if(strcmp(receivedCommand, "W1r") == 0)
         {
            StepCount = 0;
            winder.enableOutputs();
            carriage.enableOutputs();
            
    // inTempPos = Direction multiplied by Pulses Per Revolution of Winder Motor which was calculated on the PC. Positive inTempPos (Position) is CW rotation        
            inTempPos = winder_direction * PPR_WindingM;  
    
    //Just encase the winder is not at 0        
            if (winder.currentPosition() > 0)
            {
              inTempPos = inTempPos + PPR_WindingM;
            }
            winder.moveTo(inTempPos); // Move 200, 800, or whatever steps per rev you setup in the PC
            
    // Slow winding        
            winder.setMaxSpeed(250);
            winder.setAcceleration(0);

    // Set the speed of the carriage by using the calculated STEP_RATIO from the PC
            inTempPos = Speed/STEP_RATIO;
            carriage.setSpeed(inTempPos);
            carriage.setAcceleration(Accel);  // setAcceleration(Accel) doesn't work with setSpeed but, this doesn't both it
            runallowed = true;
            WME = "1";
            CME = "1";
            Send_Status();
            delay(20);
            Send_Progess();
            delay(20);
            
            
// Call the Wind-1-rev function **** NOT USING THE RunTheMotor(); FUNCTION HERE ****           
            Wind1rev();

    // New winder and carriage position
            curPosition_W = winder.currentPosition();
            curPosition_C = carriage.currentPosition();            
            EEPROM.put(0, curPosition_W);                  // Store new winder position
            delay(20);
            
    // Reset speed & accel vales        
            winder.setMaxSpeed(Speed); //set speed
            carriage.setMaxSpeed(Speed); //set speed
            winder.setAcceleration(Accel); //update the value of the variable
            carriage.setAcceleration(Accel); //update the value of the variable
            runallowed = false;
            WME = "0";
            CME = "0";
            LED_left = "0";
            LED_right = "0";
            LED_paused = "0";
            Send_Status();
            Send_Progess();
            newData = false;
            return;                                                            
         }

//HOME POSITION -  Sets the start of coil position
      if(strcmp(receivedCommand, "Sth") == 0)
         { 
            winder.disableOutputs(); //disable outputs
            carriage.disableOutputs(); //disable outputs

    // Set the winder & carriage
            curPosition_W = winder.currentPosition();                        
            winder.setCurrentPosition(0);
            Home_Position = carriage.currentPosition();  // carriage home position in real carriage position (steps), need to restore this value after coil is built

            EEPROM.put(12, Home_Position);
            delay(20);
            
            carriage.setCurrentPosition(0); // Set current position to new "new home" or start of bobbin.
            curPosition_C = carriage.currentPosition();  // Set the variable curPosition_C to the current position "new home" or start of bobbin.

            EEPROM.put(0, curPosition_W);   // Store winder position
            delay(20);
            
            EEPROM.put(4, curPosition_C);   // Store carriage position
            delay(20);           
    // Get things ready to wind 1 rev
            WindCount = 0;
            LayerCount = 0;
            LED_H_set = 1;
            WME = "0";
            CME = "0";
            LED_left = "0";
            LED_right = "0";
            LED_paused = "0";         
            Send_Status();
            Send_Progess();
            newData = false;
            return;
         }

//Start building the coil using values sent from the PC
      if(strcmp(receivedCommand, "Str") == 0)
         {
            winder.enableOutputs();
            carriage.enableOutputs();            
            Coil_Build = true;
            runallowed = true;
            WindCount = 1;
            LayerCount = 1;

    // The total winding count
            WindCountTotal = 1;

    // windings_x is the total steps needed to build the coil, (WPLayer) Windings Per Layer, (CalLayers) Total Layers Required, (PPR_WindingM) Winder Pulses per rev
    // had to use the long() convert for this to work
            windings_x =  long(WPLayer) * winder_direction * long(CalLayers) * long(PPR_WindingM); //long(x)
            PulsesPerLayer_Winder = long(WPLayer) * long(PPR_WindingM);

    // I explained most of this earlier
            winder.moveTo(windings_x);
            winder.setMaxSpeed(Speed);
            winder.setAcceleration(Accel);  // 6000

    // IT'S IMPORTANT THAT THE SEQUENCE BELOW IS IN THE RIGHT ORDER TO WORK *********************************************
            carriage.moveTo(PPLayer_C); //PulsesPerLayer_Winder/STEP_RATIO
            inTempPos = Speed/STEP_RATIO;
            carriage.setSpeed(inTempPos);
            carriage.setAcceleration(Accel);  // 6000
            
            WME = "1";
            CME = "1";
            LED_left = "1";
            LED_right = "0";
            LED_paused = "0";
            Send_Status();
            Send_Progess();
            newData = false;
            return;
         }

// STOP - Disable the motors
      if(strcmp(receivedCommand, "Stp") == 0)
         {
            runallowed = false;
            winder.disableOutputs(); //disable outputs
            carriage.disableOutputs(); //disable outputs
            WME = "0";
            CME = "0";
            LED_left = "0";
            LED_right = "0";
            LED_paused = "0";
            LED_H_set = "0";
            Send_Progess();
            newData = false;
            return;
         }

// TERMINATE/CLEAR - Sent form the TERMINATE BUTTON on the PC - Stop everything now and Reset Everything including positions except max and min limits
      if(strcmp(receivedCommand, "Clr") == 0)
         {
      // Sets a new target position that causes the stepper to stop as quickly as possible, using the current speed and acceleration parameters.
      // NOT THE SAME AS disableOutputs()
            winder.stop(); //disable outputs
            carriage.stop(); //disable outputs            
            WME = "0";
            CME = "0";
            LED_left = "0";
            LED_right = "0";
            LED_paused = "0";
            LED_H_set = "0";
            WindCount = 0;
            LayerCount = 0;
            WindCountTotal = 0;
            winder.setCurrentPosition(0);
            
            EEPROM.put(0, 0); //winder zeroed out
            delay(20);
            
            curPosition_W = 0;//Clear the bobbin start position

    //restore the carriage.currentPosition to the saved True position **************************************
            EEPROM.get(12, Home_Position); 
            delay(20);
            
            curPosition_C = Home_Position;
            carriage.setCurrentPosition(curPosition_C);
            EEPROM.put(4, curPosition_C);
            delay(20);
    ////////////////////////////////////////////////////////////////////////////////////////////////////////
            
            EEPROM.put(24, 0); //Clear the total number of windings required - NWnum
            delay(20);            
            
            Serial.print("Cleared ");
            Serial.println(Clr);
            delay(20);
            Send_Status();
            Send_Progess();
            newData = false;
            return;
         }

// Status Call for Winder and Carriage Positions
      if(strcmp(receivedCommand, "Sts") == 0)
         {
            Send_Status();
            return;
         }

// LIMIT SWITCHES - Call to Cycle Carriage motor RIGHT & LEFT to get the Limit Switches Positions. Called from PC.
      if(strcmp(receivedCommand, "Cyc") == 0)
         {
            Cycle_LimitS();
            return;
         }         
}

//========================================================================================================================================================================
//===============================================================================ROUTINES/FUNCTIONS=======================================================================

// BUILD the COIL from the calculated values from the PC
void Build_Coil()
  {
    winder.run();
    carriage.runSpeed();    // I can use runSpeed for the carriage because the drive rod is 32 threads per inch or about 153,600 steps for 6" of travel at 800 steps per rev.
    StepCount = StepCount + 1;

  // The Winding counter
    if (StepCount >= PPR_WindingM)
      {
        WindCount = WindCount + 1;
        WindCountTotal = WindCountTotal + 1;
        StepCount = 0;
      }

  // Have we made the number of windings for 1 LAYER, if yes reverse direction & and reset windings count
    if(WindCount >= WPLayer && inTempPos > 0)
      {
        winder.disableOutputs(); //disable outputs
        carriage.disableOutputs(); //disable outputs
        WindCount = 0;
        LayerCount = LayerCount + 1;
        curPosition_W = winder.currentPosition();
        curPosition_C = carriage.currentPosition();
        LED_left = "0";
        LED_right = "1";
        Send_Status();
        Send_Progess();
        delay(1000);   // a nice pause
        winder.enableOutputs();

    // IT'S IMPORTANT THAT THE SEQUENCE BELOW IS IN THE RIGHT ORDER TO WORK *********************************************
    // seems to need this reset
        carriage.moveTo(0);
        inTempPos = Speed/STEP_RATIO;
        carriage.setSpeed(-inTempPos);
        carriage.enableOutputs();
        return;
      }

  // Are we at the starting point of the coil, if yes reverse direction & and reset windings count
    if(carriage.currentPosition() <= 0)
      {
        winder.disableOutputs();
        carriage.disableOutputs();
        WindCount = 0;
        LayerCount = LayerCount + 1;
        curPosition_W = winder.currentPosition();
        curPosition_C = carriage.currentPosition();
        LED_left = "1";
        LED_right = "0";
        Send_Status();
        Send_Progess();
        delay(1000);    
        winder.enableOutputs();            
        carriage.moveTo(PPLayer_C);
        inTempPos = Speed/STEP_RATIO;
        carriage.setSpeed(inTempPos);
        carriage.enableOutputs();
        return;
      }

  // Have we made the number of windings needed, if YES stop building and send carriage back to the start position if needed "GoHome() function"
    if(WindCountTotal >= NWnum)
      {       
        GoHome();
        Serial.println("FINISHED BUILDING COIL ");        
        winder.disableOutputs(); //disable outputs
        carriage.disableOutputs(); //disable outputs        
        runallowed = false;
        BOLcarLeft == false;
        BOLcarRight = false;
        Coil_Build = false;
        WME = "0";
        CME = "0";
        LED_left = "0";
        LED_right = "0";
        LED_paused = "0";
        LED_H_set = "0";
        curPosition_W = winder.currentPosition();
        
   //restore the carriage.currentPosition to the saved True position **************************************
        EEPROM.get(12, Home_Position); 
        delay(20);
            
        curPosition_C = Home_Position;
        carriage.setCurrentPosition(curPosition_C);
        EEPROM.put(4, curPosition_C);
        delay(20);
    ////////////////////////////////////////////////////////////////////////////////////////////////////////
        Send_Status();
        Send_Progess();
        delay(1000);
        return;
      }     
    return;
}

// Move carriage Left until pause, stop, Limit Switch, or set home
void carLeft()
  {
    if (runallowed == true &&  (carriage.currentPosition() >= carMin)) //allow running - this allows entering the carriage.run() function.
      {
        checkSerial();
        carriage.run();

    // Check to see if the limit switch is closed, grounding the pin 11, once per step - STOP and store postion if low
        if (digitalRead(limSwtLeft) == LOW)
          { 
    // limit switch is closed
            carriage.disableOutputs();

    // Store Left Limit Position
            limSwLeft_Pos = carriage.currentPosition();
            EEPROM.get(20, limSwLeft_Pos);
            delay(20);
            
    // Store where we are        
            carriage.setCurrentPosition(0);
            curPosition_C = carriage.currentPosition();
            EEPROM.put(4, curPosition_C);

    // Stop running
            runallowed = false;
            BOLcarLeft = false;            
            carMin = 0;
            CME = "0";
            LED_left = "0";   
            Send_Status();
            Send_Progess();
            Serial.println("carriage is at LEFT ZERO " + carriage.currentPosition());
            delay(20);
          }
      }
    else
      {

    // Are we at the new 0 location, if so stop and set position
        if(carriage.currentPosition() <= carMin)
          {
            carriage.disableOutputs();
            carMin = 0;
            CME = "0";
            LED_left = "0";
            carriage.setCurrentPosition(0);
            curPosition_C = 0;
            EEPROM.put(4, curPosition_C);
            delay(20);
            Send_Status();
            Send_Progess();
            Serial.println("carriage is at LEFT ZERO " + carriage.currentPosition());
            delay(20);
          }
        else
          {
    // Just encase we got here by mistake
            runallowed = false;
            BOLcarLeft = false;
            //carriage.stop();
            carriage.disableOutputs();
            CME = "0";
            LED_left = "0";
            Serial.println("Outputs Disabled RUN NOT ALLOWED");
            delay(20);
            Send_Status();
            delay(20);
            Send_Progess();
            delay(20);
          }        
      }
  }

// move carriage Right until pause, stop, limit Switch, or set home =============================================================================
// SAME AS THE carLEFT FUNCTION - EXCEPT OTHER DIRECTION
void carRight()
  {
    if (runallowed == true &&  (carriage.currentPosition() <= carMax)) //allow running - this allows entering the carriage.run() function.
      {
        checkSerial();
        carriage.run();      
        if (digitalRead(limSwtRight) == LOW)
          { 
// limit switch is closed - STOP and store postion if pin 12 is low
            carriage.disableOutputs();
            runallowed = false;
            BOLcarRight = false;
            limSwRight_Pos = carriage.currentPosition();
            EEPROM.put(16, limSwRight_Pos);
            delay(20);
            runallowed = false;
            CME = "0";
            LED_right = "0";
            curPosition_C = limSwRight_Pos; //carriage.currentPosition();
            EEPROM.put(4, curPosition_C);
            delay(20);
            Send_Status();
            Send_Progess();
          }
      }
    else
      {
        if(carriage.currentPosition() >= carMax)
          {
            runallowed = false;
            BOLcarRight = false;
            carriage.disableOutputs();
            Serial.println("carriage is at carMax");
            delay(20);
            CME = "0";
            LED_right = "0";
            curPosition_C = carMax;
            EEPROM.put(4, curPosition_C);
            delay(20);
            Send_Status();
            Send_Progess();
          }
        else
          {
            runallowed = false;
            BOLcarRight = false;
            //carriage.stop();
            carriage.disableOutputs();
            CME = "0";
            LED_right = "0";
            curPosition_C = carriage.currentPosition();
            EEPROM.put(4, curPosition_C);
            delay(20);
            Serial.println("Outputs Disabled RUN NOT ALLOWED");
            delay(20);
            Send_Status();
            Send_Progess();
          }
      }
  }

//function for RUNNING the motors - CALLED FROM MAIN LOOP ==========================================================================================
void RunTheMotor() 
{
  if (runallowed == true)
    {
      checkSerial();
    
      if (BOLcarLeft == true && carriage.currentPosition() > limSwLeft_Pos)
        {
  //step the motor LEFT (this will step the motor by 1 step at each loop)        
          carLeft();        
          return;
        }
   
      if (BOLcarRight == true && carriage.currentPosition() < limSwRight_Pos)
        {
  //step the motor RIGHT (this will step the motor by 1 step at each loop)        
          carRight();
          return;
        }

      if(Coil_Build = true)
        {
          Build_Coil();
        }
    
      if (BOLcarLeft == false && BOLcarRight == false)
        {
          return;
        }
    }
  
  //program enters this part if the runallowed is FALSE, we do not do anything
  else 
    {
      runallowed = false;
      BOLcarLeft == false;
      BOLcarRight = false;
      winder.disableOutputs(); //disable outputs
      carriage.disableOutputs(); //disable outputs
      return;
    }
}

// Sends the Carriage to the Home Position when coil is done ================================================================================================
void GoHome()
{ 
  for(int i = 0; i <= 5; i++) // Just for fun
    {
      digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level) ************ FOR FEEDBACK TO PC USE ***************
      delay(500);                       // wait for a second
      digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
      delay(500);                       // wait for a second ************ FOR FEEDBACK TO PC USE ***************
    }
  
  if (carriage.currentPosition() == 0)
    {
      Serial.println("We are at the home position.");
      winder.disableOutputs(); //disable power
      carriage.disableOutputs(); //disable power
      WME = "0";
      CME = "0";
      runallowed = false;
      Send_Status();
      Send_Progess();
    }
  else
    {
      winder.disableOutputs(); //disable power
      carriage.setMaxSpeed(400); //set speed manually to 400. In this project 400 is 400 step/sec = 1 rev/sec.
      carriage.enableOutputs(); //enable pins
      WME = "0";
      CME = "1";    
      carriage.moveTo(0); //set abolute distance to move
      CME = "0";
      Send_Status();
      Send_Progess();
    }
}

// Winds 1 winding on the bobbin ============================================================================================
void Wind1rev()
{
  if (runallowed == false)
    {
      winder.disableOutputs();
      carriage.disableOutputs();
      Serial.println("Outputs Disabled RUN NOT ALLOWED");
      WME = "0";
      CME = "0";
      WindCount = 0;
      LayerCount = 0;
      Send_Status();
      Send_Progess();
      return;
    }

  if (runallowed == true)
    {
      Send_Progess();
      do
        {
          winder.run();      
          StepCount = StepCount + 1;
          if (StepCount >= STEP_RATIO)
            {
              carriage.move(carTempPos);
              carriage.runSpeed();
              carTempPos = carTempPos + 1;
              StepCount = 0;
            }
        
          if(winder.currentPosition() == inTempPos)
            {
              runallowed == false;
              winder.disableOutputs();
              carriage.disableOutputs();
              carTempPos = 0;
              WME = "0";
              CME = "0";
              curPosition_W = winder.currentPosition();
              EEPROM.put(0, curPosition_W);
              delay(20);
              curPosition_C = carriage.currentPosition();
              EEPROM.put(4, curPosition_C);
              delay(20);
              WindCount = WindCount + 1;
              WindCountTotal = WindCountTotal + 1;
              LayerCount = 1;
              Send_Status();
              Send_Progess();
              delay(500);
              break;
            }
        } while(winder.currentPosition() != inTempPos);
      return;
    }
}

//Cycles the Carriage to find the Limit Switches and store their position values ==========================================================================
void Cycle_LimitS()
{
  {
    winder.disableOutputs();
    carriage.enableOutputs();

 // Get the carriage position   
    EEPROM.get(4, curPosition_C);
    carriage.setCurrentPosition(curPosition_C);

 // Are we at less than Max right, if so move to Max right
    if (curPosition_C <= carMax)
      {
        carriage.moveTo(carMax);
        carriage.setMaxSpeed(Speed);
        carriage.setAcceleration(Accel);
        WME = "0";
        CME = "1";
        LED_left = "0";
        LED_right = "1";
        LED_paused = "0";
        LED_H_set = "0";
        Send_Status();
        Send_Progess();

    // LOOP - Run the carriage to the right until carMax or the limit switch closes
        while(curPosition_C <= carMax)
          {
            carriage.run();
            if (digitalRead(limSwtRight) == LOW)
              { // limit switch is closed
                carriage.disableOutputs();
                limSwRight_Pos = 1;
                carMax = carriage.currentPosition();
                EEPROM.put(8, carMax);                              
                delay(20);
                break;
              }          
          }

    // Store MAX RIGHT position
        limSwRight_Pos = carMax;
        EEPROM.put(16, limSwRight_Pos);
        delay(20);
        curPosition_C = carriage.currentPosition();
        EEPROM.put(4, curPosition_C);
        delay(20);
        CME = "0";
        LED_right = "0";
        Send_Status();
        Send_Progess();
        Serial.println("Carriage is at RIGHT LIMIT");
        delay(1000);
      }
      else

    // We are at MAX RIGHT already
        {            
          Serial.println("Carriage is all the way RIGHT");
          delay(20);
          curPosition_C = carriage.currentPosition();
          delay(20);
          carriage.disableOutputs();
          EEPROM.put(4, curPosition_C);
          delay(20);
          CME = "0";
          LED_right = "0";
          Send_Status();
          Send_Progess();
        }
    delay(500);    // A little pause before changing directions

    // move left to carriage limit left limit or to carMin
    if (digitalRead(limSwtRight) == LOW) 
      {
        EEPROM.get(4, curPosition_C);
        delay(20);
          if (curPosition_C > 0)
            {
              carriage.enableOutputs();
              carriage.setCurrentPosition(curPosition_C);

    // The negative "-" changes MOTOR direction
              carriage.moveTo(-carMin);
              carriage.setMaxSpeed(Speed);
              carriage.setAcceleration(Accel);
              WME = "0";
              CME = "1";
              LED_left = "1";
              LED_right = "0";
              LED_paused = "0";
              LED_H_set = "0";
              Send_Status();
              Send_Progess();

    // LOOP - Run the carriage to the left until carMax or the limit switch closes
              while(carriage.currentPosition() > 0)
                {
                  carriage.run();
                  if (digitalRead(limSwtLeft) == LOW)
                    { // limit switch is closed
                      limSwLeft_Pos = 1;
                      break;
                    }
                }

    // Store MAX LEFT position                
              carMin = carriage.currentPosition();            
              EEPROM.put(20, carMin);
              delay(20);
              carriage.setCurrentPosition(0);
              curPosition_C = carriage.currentPosition();
              EEPROM.put(4, curPosition_C);
              delay(20);            
              CME = "0";
              LED_left = "0";
              Send_Status();
              Send_Progess();
              Serial.println("Carriage is at LEFT LIMIT");
              delay(20);
          }
        else
          {
    // We are at MAX left already
            carriage.setCurrentPosition(0);
            curPosition_C = carriage.currentPosition();
            EEPROM.put(4, curPosition_C);
            delay(20);
            CME = "0";
            LED_left = "0";
            Send_Status();
            Send_Progess();
            Serial.println("Carriage is all the way LEFT");
            delay(20);
          }        
      }
      return;
  }
}

//INDIACATORS ===========================================================================================================================
void Send_Progess()
{
//This is sent back to the PC
//WME, CME, LED_left, LED_right, LED_paused, LED_H_set, WOWINDING, WOLAYER
//eg. I,11100111,######,###  this what is sent to PC
// + ',' + WME + ',' + CME + ',' + LED_left + ',' + LED_right + ',' + LED_paused + ',' + LED_H_set + ',' + WOWINDING + ',' + WOLAYER
//eg.I      1           0             1                 0                 0                 0                000001            001   //18 characters

  sprintf(WOWINDING, "%09d", WindCountTotal);
  sprintf(WOLAYER, "%04d", LayerCount);
          
  String dataout = (indOUT + WME + CME + LED_left + LED_right + LED_paused + LED_H_set + WOWINDING + WOLAYER); // + "\n"
  Serial.println(dataout);
  delay(20);
  return;
}

// =====================================================================================================================================
// Send the positions of the winder and carriage to the PC in # of steps !!!CAN NOT BE CALLED TOO OFTEN - WILL SLOW THE STEPPERS A LOT
void Send_Status()
{
  char W[10];
  char C[10];
  
  sprintf(W, "%09ld", curPosition_W);
  sprintf(C, "%09ld", curPosition_C);
  String strSts = (STSout + W + C);
  Serial.println(strSts);
  delay(20);
}
// End of PROGRAM---------------------------------------------------------------------------------------------------------------------------------
UMT's Coil Winder applicationC#
Windows PC Program
No preview (download only).

Schematics

Customizable Coil Winder
Pictorial Diagram

Comments

Similar projects you might like

Arduino Musical Tesla Coil

Project in progress by Brandon Michelsen

  • 11,999 views
  • 5 comments
  • 17 respects

Scorbot ER-V+ Controller & Simulator Design

Project tutorial by Amit Nandi (BigWiz)

  • 1,558 views
  • 3 comments
  • 6 respects

IoT Tesla Coil and Cooling Fan on the Localhost

Project tutorial by Kutluhan Aktar

  • 2,414 views
  • 1 comment
  • 7 respects

Big Track Rover "ENHANCED EDITION" Obstacle Avoidance Bot

Project showcase by Sam

  • 1,690 views
  • 1 comment
  • 3 respects

Control Pie Face Wirelessly with Your Phone!

Project showcase by HarrisonMcIntyre

  • 1,283 views
  • 0 comments
  • 8 respects
Add projectSign up / Login