Coil Winder using Easy Driver - I want faster stepper rotation

I built a simple coil winder to make guitar pickups (simple coil on a bobbin in which the core is made of rod magnets):

Basically I am happy with my little machine in every respect except for speed. I would like for it to go about 3x faster without using any gears - IT HAS TO BE DIRECT DRIVE.

When I wind a pickup by hand by just clamping the bobbin into a lathe, it takes just a few minutes. With my Arduino winder, I start it winding, turn off the lights, and let it run for 32mins up to > 1hr. I would like for the Arduino winder to hit about 1000 RPM.

I am using the Easy Driver board to drive this stepper to get the rotation: Stepper motor NEMA 17 76oz/in 11V | eBay

I am powering the Arduino and the Easy Driver with a smallish 9v DC transformer (at 12v the Easy Driver goes directly from too hot to stalling). Also the servo is powered from the Easy Driver 5v output pin.

I am open to making my code better, trying a more robust driver board, buying a PSU, etc. I'm probably not willing to design my own board or anything like that - I'm looking for a quick fix, not another whole project. I just don't know what I need to do to make the same basic project MUCH FASTER.

Here is my code in case there are any opportunities for more speed there.

#include <Servo.h> 


//User Variables - Use these to customize the coil.
int turnsCount = 7800;       //how many turns
float bobbinHeight = .436; //height in inches
int turnsPerLayer = 120;  // how may turns per traverse?

#define DIR_PIN 8
#define STEP_PIN 9
Servo myservo;

// Variables and Constants - Do Not Edit ************************
// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin  
// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers
int stage = 0;  //enter 2 to use set variables
int pos = 3;    // variable to store the servo position 
float stepSpeed=.02;           //stepper speed to feed into rotateDeg loop

//pulley diameter is 0.378 inches, therefore its total max travel is 0.593761, so each clicks moves it about 0.00329867
const float totalTravel = 0.593761;  //inches that each degree of servo rotation moves the traverse belt
float moveBy = bobbinHeight/turnsPerLayer;
float currDist = 0.000000;  // running tally of distance from starting point
int servoDir=1;  // direction of servo, i.e. traverse movement. 1 for up and -1 for down


//Setup**********************************************************
void setup() { 
  Serial.begin(9600);      // open the serial port at 9600 bps:
  pinMode(DIR_PIN, OUTPUT); 
  pinMode(STEP_PIN, OUTPUT); 
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  digitalWrite(buttonPin, HIGH);
  Serial.begin(9600);      // open the serial port at 9600 bps:
  myservo.attach(6);        // attaches the servo on pin 6 to the servo object LD
  myservo.write(3);           // set up servo in position at edge of bobbin
} 


//Main Loop******************************************************
void loop(){
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);
  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  
  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  } 
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = reading;
    if(reading == LOW){ //this is definitely a debounced button press
    stage += 1;       
    delay(1000);                  
    }
    
  }
 
//Stage 1 - button has been pressed, machine is winding the pickup
     if (stage == 1){  
      if (stepSpeed < 1){ //still ramping up speed
        stepSpeed += .02;
      }
      
          if (turnsCount>0){ //still winding - stepper only turns inside this loop
            //rotate a specific number of degrees 
            rotateDeg(360, stepSpeed);
            turnsCount-=1;
            
                  //servo code  ****************************************************************               
                  currDist=servoDir*moveBy+currDist;
                  
                  if(currDist>=bobbinHeight){  //reached limit, start moving back toward 0
                    servoDir=-1;
                    currDist=bobbinHeight;
                  }
                  if(currDist<=0){   //at 0, start moving up again
                    servoDir=1;
                    currDist=0;
                  }
                  

                  pos=(currDist/totalTravel*180)+3;  //write new servo rotation based on calculations
                  myservo.write(pos); 
                  
                  
                                    
                  Serial.print("remaining: ");
                  Serial.print(turnsCount);  //print the current stage
                  Serial.print("  \n"); 
                  
          
        
          }
      }
}






// turns the stepper one full revolution *************************
void rotateDeg(float deg, float speed){  
  //rotate a specific number of degrees (negitive for reverse movement)
  //speed is any number from .01 -> 1 with 1 being fastest - Slower is stronger
  int dir = (deg > 0)? HIGH:LOW;
  digitalWrite(DIR_PIN,dir); 

  int steps = abs(deg)*(1/0.225);
  float usDelay = (1/speed) * 70;

  for(int i=0; i < steps; i++){ 
    digitalWrite(STEP_PIN, HIGH); 
    delayMicroseconds(usDelay); 

    digitalWrite(STEP_PIN, LOW); 
    delayMicroseconds(usDelay); 
  } 
}

Serial output may be slowing you down a little - increase the baud rate and/or print less frequently. More obviously though, how much can you reduce the delays in your rotateDeg routine?

Statements like "delay(1000)" and floating point(very slow!) are not consistent with hi speed loops.

  1. Cut down to a simple program that simply steps the motor. Increase the stepping rate until the motor reaches its practical limit without complicating code.
  2. Remember that the stepper controller has a current adjustment pot. Higher current may allow higher step rates within the thermal limits of the motor. But check #1 first.

Worry about the hardware, only if the above fails to achieve adequate speed.

This sounds like an application for a regular DC motor with a simple encoder so the Arduino can count the number of turns. It could go as fast as you wanted with the speed controlled by PWM. Cheaper, simpler.

...R

If you want the motor to spin more quickly then you need to use a higher voltage motor power.

If the Easydriver is overheating then the first thing to do would be to remove the servo power from it -- taking power from the Arduino would be better. Having the servo connected here and increasing the input voltage to the driver will exacerbate that problem as well. The next thing to do would be to stick a heatsink on the EasyDriver driver chip. Right now the only heatsink the chip has is the PCB itself; blowing on it with a fan would help also.

This sounds like a promising lead. I would like to tinker with this.

I did a Google search and found this board that has a tutorial on how to use it: Ardumoto Shield Hookup Guide - SparkFun Learn

Okay I understand how I could use that to control the speed of the motor, but I don't understand how I could keep track of turns.

Robin2:
This sounds like an application for a regular DC motor with a simple encoder so the Arduino can count the number of turns. It could go as fast as you wanted with the speed controlled by PWM. Cheaper, simpler.

...R

BTW I will try the other suggestions, too. I remember I messed with the delay in the rotation routine, but it made the motor stall. Maybe I will try to find a safe threshold...

Okay I have tried all suggestions. The motor hangs under any circumstances with delay less than 70 with the rest of the code staying the same.

I am now using a 20v PSU - regulated, switching PSU from a very old laptop. The motor sounds different but I'm still at about 250RPM (figured with a stopwatch).

I want to try to get rid of floating point calculations, but how?! I think I am missing a basic thing here. I understood that in order to do any calculations with decimals, I have to use FLOAT type? What if I say I can have all numbers for the servo calculations to out to ten thousandths (i.e. 0.000x). How can I do that with a variable type that doesn't slow the Arduino so much?

I understood that in order to do any calculations with decimals, I have to use FLOAT type?

No, not necessarily - if, for instance, you only count in units of one ten-thousandth of a whatever, then you can use large integer types.
You can fit +/- 214748 1/10000ths in a 32 bit signed integer.
If a "whatever" is a millimetre, that's an accuracy of 1/10000th of a mm over a distance of over 200 metres.

The exact mechanical details for keeping track of turns can vary widely but the general idea is to have a disk that rotates with the bobbin. The disk could be white with a black stripe on it (or several stripes if you need to count part turns). You would use a photodiode to detect the difference between black and white and cause one of the digital inputs to the Arduino to switch from high to low etc. A variation on this would be a disk with a hole in it that lets light through to the photodiode.

Your Arduino sketch would then count how many times the signal changes.

If the encoding disk is attached to the bobbin it doesn't matter what gear ratio there might be between the motor and the bobbin - which might allow you to use a very cheap motor.

...R

I'd not use a stepper motor for winding a bobbin, they have way way too much torque and
vibration for thin wires. Smallish DC motor with speed control and encoder to count the
turns would be simple and work well.

To get a stepper motor going fast needs all of these:

a) the right motor - low inductance windings (for Nema 17 any motor with 2 ohm or
less windings would be good - what's the resistance of yours?

b) High supply voltage (48, 60 or even 80V is common)

c) A suitable chopper drive with microstepping that isn't overloaded at the full rated current for the motor.

Oh okay I get it. So I will be counting turns with a sensor, instead of counting instructions sent to the motor. That makes perfect sense. My hand winder is kinda like that - a bicycle computer uses a proximity sensor (or maybe hall effect senseor?) to count each physical revolution of a plate that is belt-driven (re-purposed wood lathe). On that one I just watch for the display to hit the number I want and turn it off manually (I'm sitting there to hand guide the wire, anyway, so it's not worthwhile to automate anything on that one.

I bought one of these at the same time I got the Easy Driver: http://cgi.ebay.com/ws/eBayISAPI.dll?ViewItem&item=150765336052 It says $96.05 now but I'm sure I paid literally a few bucks for it. I'm gonna see if I can't get started moving a DC motor with that. I have a proximity sensor in parts box, too. Do those work at speeds around 1000RPM, or would something optical as suggested be more reliable?

Yeah, a chopper stepper driver is required if you are getting anywhere near the stall speed of the stepper.

A hall effect device should work to 1000rpm, after all that is only about 17Hz.

polymorph:
Yeah, a chopper stepper driver is required if you are getting anywhere near the stall speed of the stepper.

Steppers don't have a stall speed. There is a pull-out torque that varies with speed and driver
voltage/type...

Do you have a spec sheet on the stepper you are using? You may find that 250rpm is it.
The spec should tell you what are the optimum conditions for the stepper to run at its maximum speed.
Tom.

The torque reduces as the speed increases. The torque at higher speeds is greater when using a chopper driver. There is another technique involving using a much higher voltage than the stepper rated voltage, with current limiting resistors. But that is kind of a Flintstones era way to get around using a stepper driver.