Simple way to control stepper speed with potentiometer input

Hello everyone

Does anyone know of a simple method to control the speed of a stepper with a potentiometer?
I have found the speedy stepper library for arduino but couldn’t get it to work yet, and maybe someone has a better idea.

Background:
I recently got an old sewing machine (built mid 50ies) which works like a charm, but can only go fast and even faster. Since I’m a beginner at sewing I’d like it to go slower. I’ve figured out the mechanical side, decouple the original motor from the machine (this is even a built in function for winding bobbins), replace the hand wheel with a 3d printed one which has a GT2 gear and use a belt to drive it with a nema17. This gives me a 5:1 reduction, so less speed and more power, plus the stepper motor allows to reduce the speed even further.
Now for the electronics side, I imagined something like build a simple foot pedal with a potentiometer, connect that to an arduino or similar board, which then sends step signals to an A4988 stepper controller.
Software side should be easy, read analog input, if it’s over a threshold start running the stepper, update speed continuously depending on the input.
Bonus idea for when I get this running: add a switch to change to single stitch mode. When the pedal is pressed down, do a single revolution (motor steps * microsteps * reduction ratio) at a fixed speed, pedal has to be released and pressed down again to do another stitch.

Let me know if you have a good idea, otherwise I’m continuing to experiment with the stepper libraries by Stanley Reifel :slight_smile:

Edit: just found another library which might be better suited for this application: SpeedStepper library

Edit 2: Or probably even better suited: AccelStepper

Hello there!

I don’t have a direct answer to your question, but I want to chime in none the less, since the situation is quite similar.

I’ve been meaning to make my wife an electric spinning wheel, for spinning yarn. I’ve found a thingiverse/github project that runs a machine with variable speed and tension. It sounds like a similar situation - but the motor is different, so it’s not fully applicable. But who knows, maybe there’s something useful to it? This project uses a brushless dc motor with hall sensor, run with a potentiometer and a foot switch: Electric Spinning Wheel by ChPech - Thingiverse / github.com/ChristophPech/Spinner

Thank you for the input :slight_smile:

I’m gonna try to get it working this weekend, and I probably won’t even need any fancy stepper libraries, just analogRead(), delayMicroseconds() and digitalWrite()

I also found a way to increase analog input sampling frequency:
http://yaab-arduino.blogspot.com/2015/02/fast-sampling-from-analog-input.html

Without that a single sampling takes 100 microseconds, which would put the maximum speed at about 1 stitch per second with 1/8 microstepping.

1 Like

I’ve used AccelStepper with an esp32 before and it worked well. I was stepping very slow though. Just because that was my need.

You may also want to consider using PWM because it can keep on stepping while you do the analog read. You should be able to adjust the frequency to adjust the speed.

You don’t need to read every step, only 10/s or so. People aren’t going to be changing the desired value that much.

You should also know about debounce. You can do it in software, with a low pass filter, but a circuit would mean fewer analog reads while having a more responsive pedal.

1 Like

Are you 100% committed to using a stepper motor? This would be easily done with off-the-shelf parts using a DC motor.

You could also get there with an AC motor coupled with the PWM AC Dimmer from the V1 Shop. You can use a simple 5K pot as the PWM input if you don’t need feedback for a full RPM control solution.

1 Like

Yes, I’m set on the stepper motor and potentiometer, because they are spare parts just lying around, don’t need to order anything new.

Good idea with the pwm, but I’m not sure if it can keep count of the number of steps it has done. But then again, I could do pwm for the speed control, and manual steps in a for loop for the single stitch mode…

Wait, pwm is a fixed frequency, and only changes the duty cycle, so this wouldn’t work. Unless there is a way to change the pwm frequency.

I just did a quick and dirty little stepper motor control for Arduino, using a leftover Polulo A4988, a 10k trimpot and an arduino.

I didn’t really care about speed, I was looking for position. (It is for a focus mechanism for a DIY projector)

I have a very simple setup, I advance the stepper forwards until I hit a limit switch (aka an input wire that touches a ground wire) at infinite focus, then count steps the other way until I hit the other limit switch (Another input wire that touches ground) Set a step count to zero.

I then put the pot on an analog read pin (Gives me a value from 0 to 1023) and advance the stepper motor proportionally whatever number of steps that is, and loop. Change the pot value, it moves the focus, then leaves it alone. Power cycling the Arduino will cause it to travel to infinite focus and back to close focus again, but it will immediately go back to where you left it before.

With the polulo driver, if I wanted something that would just spin the motor. it should be easy enough.

Give a set pulse time and define a range of interval timers for min/max RPM (Probably a motor reverse switch, too)

Enable the driver, set the direction pin and start pulse the step pin

Read the analog input pin and stake a timer for the next pulse. rinse and repeat.

I grabbed example code from here for driving the A4988, but ended up not using the accel library, because frankly, I didn’t need it. I was doing things slowly enough that I could just jump in and move.

At one point I read a blog from a dude that built a simple circuit with a 555 timer chip and a potentiometer. It was used to control a stepper like your are suggesting. No code involved. Not sure if that knowledge is helpful here.

https://www.arduino.cc/en/pmwiki.php?n=Tutorial/SecretsOfArduinoPWM

Not through the arduino helper functions but you can vary the frequency by changing the registers, like OCRA.

It is not as hard as it looks, but it is an intermediate level of difficulty. It would be necessary if the analog read was taking too long.

You can adjust the timer used for PWM signals. Different pins use different timers, but I don’t suggest this as a solution. As someone who marched down this pathway last year, how much work you need to do will depend on 1) how fast you want to spin your stepper and 2) how accurately you want to spin your stepper. If you are willing to live within the limits, AccelStepper() will do the job. If you want to do it yourself, as a starting point (assuming your stepper enable pin is enabled), all you have to do to move the motor is something like this:

void loop() {
  digitalWrite(PIN_STEP, HIGH);
  delay(someTime);
  digitalWrite(PIN_STEP, LOW);
  delay(someTime);
}

To this you will need to add code that check your potentiometer at some set interval (not every loop() call), and you may also want to average the reading since the values returned by analogRead() from a mechanical potentiometer will float around some.

If you need it to spin faster, you can replace delay() with delayMicroseconds(). There are 1000 microseconds in a millisecond.

If you need faster still, you will start to run into issues. You will need to adjust your pulses based on the extra time it takes you to read your potentiometer, and the stock digitalWrite() is slow. You can directly write to the pins, but the digitalWriteFast library will get you most of the speed of directing accessing the pins.

The next step beyond this would be to drive the stepper from a timer interrupt. This is what I did when building a motorized Phenakistoscope last year to play disks like these. I needed to spin the stepper very quickly and precisely. IMO, using a timer is a far superior method for quickly and accurately spinning a stepper, but unfortunately it is fairly complicated (at least for me). That is, setting up timers for arbitrary calls per second is complicated. If you need to go down this road of using a timer for accuracy and/or speed, I’d be glad to pull out the relevant code from my project to get you started.

You might be right Robert. I haven’t tried it myself.

My assumptions are these:

  1. when doing speed control, exact position isn’t critical.
  2. analogRead is going to be slow enough to make it interfere with bit banging. IIRC, interrupts get disabled during analogReads.

I’d be happy to be wrong.

If analogRead takes 100us, which is just an approximation, you could step at about 10kHz. With 1/16th microstepping and 200 steps/rotation you would get about 3 rotations per second. If you only polled analogRead every 100ms, you could go much faster, but there would be small pauses during the read. I don’t really know how long those need to be before they would start causing problems though.

It would be very smart to start with just accelStepper and get something you can do some real testing with. This argument is really just academic until you decide it isn’t working fast enough.

I don’t want to be a party pooper, this forum is simply amazing - buuut, a thought came to my mind: is a stepper motor strong enough to run a sewing machine? It occurs to me that the motors in such machines are quite powerful. The creator of the electric spinning wheel has claimed that steppers are to weak for spinning, but I don’t know if the same counts for sewing machines.

1 Like

I think with the 5:1 reduction it should be plenty strong, but with the analog read on every step it would bring the macimum speed down to less than 1 stitch per second.
I’m just now setting everything up to start experimenting :slight_smile:

My plan for now is this:
Poll the analog read for every step, but set the clock divider from 128 to 16 to get the read time down to about 20us. Digital write takes about 4us, so this gives me, together with the rest of the code a theoretical cycle time of roughly 40us, or 25k steps per second, 1000 full steps per stitch and 1/4 microstepping should give me a maximum of 6 stitches per second, which is about the upper limit I would want it to go.

If this works, I’ll do the single stich mode which runs at a fixed speed which ramps up and down at the begining/end of the stitch.

1 Like

You need both on and off to trigger a step, though they don’t have to be even. You just need a pulse width long enough to trigger the stepper driver, and that will depend on your stepper driver. Looking at stepper driver datasheets, I found the numbers varied significantly. The standard analogRead() takes 112us on an Uno, much longer than the 20 you have listed, but there is a library that provides faster version of analogRead() that will get it down to 21us. And if you are running near your maximum RPM, you will have very little torque. You’ll have to do some tests, but it might be better to run slower using a more aggressive gear ratio.

My personal solution for my application was to use an interrupt driven rotary encoder to control the speed rather than a potentiometer. It dodged the whole analogRead()-time issue. A bit hacky, but you could have an interrupt driven push button to “set” a new speed, and only do the analogRead() if the button is pressed.

Jeffeb3: 1. when doing speed control, exact position isn’t critical.

In my particular application, I was synchronizing a strobe with the rotation, so exact position was critical. But you are right for Raphael. Having the speed wander a bit when sewing would not be an issue. As mentioned above, I didn’t deal with the analogRead() delay since I used a rotary encoder.

1 Like

Sooo, some successes, some failures :sweat_smile:

At first I couldn’t get anything to run at all. Turns out I was working with a broken arduino AND a broken stepper driver :see_no_evil:

So I soldered up everything again and got the motor spinning :slight_smile:

Good news, analogRead won’t be the bottleneck, bad news, I can’t get the stepper turning any faster than 7 revolutions per second. If I try any faster it stalls and just vibrates. I tried different microstepping settings and higher motor currents, but 7 rps seems to be the upper limit.
With 1/4 microstepping that turns out to about 180us per step, so plenty of time to do an analog read, do a bit of math and set an output :slight_smile:

I’ll change the gear ratio to 2:1 and see if that will be strong enough to turn the machine :slight_smile:

How long is your step pulse duration?

You should try higher source voltage. Steppers fight back with voltage when they are moving fast, which can lead to the driver not being able to push enough current even if it is set high.

But, there are always trade offs and it is probably good to start from something that works and try to improve it, instead of waiting until everything is optimal before using it.

Actually, with acceleration I can get it to spin at 10 rps, or 125us delay between steps, so I have some head room :slight_smile:

I can’t get any higher voltage right now, the stepper is running on 12v from a pc power supply. This really is a recycling project with whatever old parts I could find…

Now to 3d print the pulleys…

Got the electronics and software side working, here’s the code for continous stitching with variable speed:

#define DIR 5
#define STEP 6
#define POTI 14
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

void setup() {
  pinMode(DIR, OUTPUT);
  pinMode(STEP, OUTPUT);
  digitalWrite(DIR, HIGH);
  sbi(ADCSRA, 1);
  cbi(ADCSRA, 1);
  cbi(ADCSRA, 0);
}

void loop() {
  int value = analogRead(POTI);
  if (value >= 50){
    int d = map(value, 0, 1023, 1000, 10);
    digitalWrite(STEP, HIGH);
    delayMicroseconds(d);
    digitalWrite(STEP, LOW);
  }
  else {
    delay(10);
  }
}

And here’s the code for single stitches:

#define DIR 5
#define STEP 6
#define POTI 14
bool ISPRESSED = false;

void setup() {
  // put your setup code here, to run once:
  pinMode(DIR, OUTPUT);
  pinMode(STEP, OUTPUT);
  digitalWrite(DIR, HIGH);
}

void loop() {
  if (!ISPRESSED && (analogRead(POTI) > 200)) {
    ISPRESSED = true;
    int d = 0;
    for(int i=0; i<4000; i++) {
      if (i < 100) {
        d = 1260-i*12;
      }
      else {
        if (i<3900) {
          d = 60;
        }
        else {
          d = 1260-((4000-i)*12);
        }
      }
      digitalWrite(STEP, HIGH);
      delayMicroseconds(d);
      digitalWrite(STEP, LOW);
      delayMicroseconds(d);
    }
  }
  if (analogRead(POTI) < 50) {
    ISPRESSED = false;
  }
  delay(10);
}

Now I just have to assemble everything and see if the sewing machine will run.