Simple way to control stepper speed with potentiometer input

It works! :smiley:
Didn’t have much time to work on it today, but I managed to merge the 2 programs into one and added the switch to select which one to run.

I assembled everything quickly and tested it, and it works. But if it accelerates too fast the motor stalls, I’ll try to increase the motor current or get a 24v psu.

But I messed up the gear ratio, instead of 5:1 I made an 8:1 reduction, I’ll print new gears and see if it will work better. Since stepper motors have higher torque at lower speeds it could work out better.

And I’m working on the foot pedal.

I’ll post some pictures later :slight_smile:

2 Likes

You can get some cheap acceleration limiting by keeping the previous speed in a global variable. Outside the loop/setup, you would do this:

int prevValue= 0;
const int maxValChange = 50;

In the loop, you would do something like this:

int value = analogRead(POTI);
value = std::min(value, prevValue + maxValChange); //don't speed up too quickly
value = std::max(value, prevValue - maxValChange); // don't slow down too quickly
prevValue = value; // store for next loop
...

If you had a value of 0, and then 155, the value would go 0, then 50, then 100, then 155. You can adjust the maxValChange to make it more responsive, or slower. You can also choose a different value for the max as the min, so it could stop faster.

3 Likes

Great idea, this should deffinitely keep the motor from stalling :slight_smile:

2 Likes

For some reason it won’t work…

is there anything I messed up in the code?

int d = map(value, 0, 1023, 1000, 10); //map input to delay time
d = max(d, prev_d - MAXACC); //limit acceleration
prev_d = d; //store delay for next loop
digitalWrite(STEP, HIGH);
delayMicroseconds(d);
digitalWrite(STEP, LOW);

Even if I set MAXACC to 1 it doesn’t seem to limit acceleration.
Note that I only care about positive acceleration, meaning d getting lower, when the pedal gets released I want it to stop instantly, so no deceleration limiting.
I’m not sure what this std:: is supposed to do, is it neccessary for it to work?

Then you need the min line, not the max.

If d is 155 and prev_d is 0, then it would be this:

value = min( 155, 0 + 50 );

Which would limit it to 50.

Pretty sure I need the max function, since lower number means motor spins faster.
I tried the min at first, but that didn’t work either…

Wait, do I need to include math or any other library for those functions to work?
I’m trying it with constrain() now…

Oh, I wrote it to work on the pedal output, not the delay output. Yeah, the min is right. That should work, if it compiles.

It does compile, and shouldn’t need any other libraries, min/max/constrain are all included by default.
I think I have to test the code with a simpler example to make sure it works, or figure out why it doesn’t…

Because in the single stitch code I already have an acceleration ramp:

for(int i=0; i<4000; i++) {
      if (i < 100) {
        d = 1260-i*12;
      }

This decreases the delay by 12 for every step (or rather 24, since delayMicroseconds(d) gets called twice). But even with MAXACC set all the way down to 1 it doesn’t change the behavior in the slightest bit… So something has to be wrong with my code, I just haven’t found it yet.
I’ll try to do some tests with the serial plotter, recording d before and after constraining it should point me in the right direction…

Also, to cycle back to the beginning of this thread, I just found the tone() function, which does the opposite of PWM. It allows to set a frequency with which an output pin gets switched, with a fixed 50% duty cycle.

1 Like

Ok, my sanity is restored. It turns out the code was working, but even a maximum acceleration of 1 was too much. Because my problems were physical; I forgott to decouple the motor of the sewing machine, which was roughly doubling the load on the stepper.

Everything works, the pedal pieces are printing right now, and I can go to bed :slight_smile:

If anyone is interested in the finished code, here it is:

#define DIR 5
#define STEP 6
#define SINGLE 7
#define POTI 14
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
const int MAXACC = 1;
int prev_d = 1000;
bool ISPRESSED = false;
int d = 1000;
int value = 0;

void setup() {
  pinMode(DIR, OUTPUT);
  pinMode(STEP, OUTPUT);
  pinMode(SINGLE, INPUT);
  digitalWrite(DIR, HIGH);
  sbi(ADCSRA, 1);
  cbi(ADCSRA, 1);
  cbi(ADCSRA, 0); //these 3 lines increase analogRead() speed
}

void loop() {
  if (digitalRead(SINGLE)) { //single stitch mode
    if ((ISPRESSED == false) && (analogRead(POTI) > 200)) {
      ISPRESSED = true;
      for(int i=0; i<4000; i++) {
        if (i < 400) {
          d = 1300-i*3; //accelerate
        }
        else {
          if (i<3900) {
            d = 100;
          }
          else {
            d = 1300-((4000-i)*12); //decelerate
          }
        }
        digitalWrite(STEP, HIGH);
        delayMicroseconds(d);
        digitalWrite(STEP, LOW);
        delayMicroseconds(d);
      }
    }
    if (analogRead(POTI) < 50) {
      ISPRESSED = false;
    }
  }
  else { //continuous stitch, variable speed mode
    value = analogRead(POTI);
    d = map(value, 0, 1023, 500, 5); //map input to delay time
    d = max(d, prev_d-MAXACC); //limit acceleration
    prev_d = d; //store delay for next loop
    if (value >= 50){
      digitalWrite(STEP, HIGH);
      delayMicroseconds(d);
      digitalWrite(STEP, LOW);
    }
    else {
      delay(10);
    }
  }
}
3 Likes

Late to the party here, but if all you want to do is control speed of a stepper, this device, available for about $15 will do it for you- just connect the step/dir/enable to the motor driver, hook up power, and you’re good to go:

This is a very handy device to have around if you work with integrated motors or driver modules for steppers or servomotors.

4 Likes

Good to know for any future project :smiley:

Looks to me like it’s cheaper on Amazon… That’s unusual.