Move a stepper using potentiometer's rotation

Hello! I'm trying to build a servo arm using Arduino and a rotating base using a stepper motor. Stuck on the last part, I'm using 28BYJ-48 5V, AccelStepper and trying to accomplish an accelerating movement to a desired location set by a potentiometer. The idea is to detect whether the potentiometer is moving or not, then wait for it to stop changing values, and if that happens - start moving the stepper to potentiometerValue mapped with -1024, 1024, because that creates a 180-degree movement. It doesn't seem to work. I'm no master programmer, so I figured I'd done something wrong. Can someone correct my code or suggest alternatives?

Here's the code:

#include <AccelStepper.h>
#define HALFSTEP 8

#define POTENTIOMETER_PIN A0
int potentiometerValue = 0;
int previousPotentiometerValue = 0;
int movePosition = 0;

AccelStepper stepper(HALFSTEP, 8, 10, 9, 11);

bool checkPotentiometerRotation() {
  if (potentiometerValue - previousPotentiometerValue > 10 || potentiometerValue - previousPotentiometerValue < 10) return true;
  else return false;
}

void setup() {
  Serial.begin(9600);
  
  pinMode(POTENTIOMETER_PIN, INPUT);

  stepper.setMaxSpeed(1000.0);
  stepper.setAcceleration(100.0);
  stepper.setSpeed(300);
}

void loop() {
  potentiometerValue = constrain(analogRead(POTENTIOMETER_PIN), 8, 1015);

  while (checkPotentiometerRotation()) {
    previousPotentiometerValue = potentiometerValue;
    delay(200);
    potentiometerValue = constrain(analogRead(POTENTIOMETER_PIN), 8, 1015);
  }

  if (stepper.distanceToGo() == 0) {
    map(movePosition, 8, potentiometerValue, -1024, 1024);
    stepper.moveTo(movePosition);
  }
  stepper.run();
}

Can you please explain why you are not using a servo motor? If you can't, then the answer might be quite simple.

I'm only using the stepper motor for the base, because it provides a smoother, non-rapid movement. Apart from that it needs to handle some weight (3 servos, some plastic staging and a claw), which, I don't think, a servo can do. What's the "quite simple answer" you're talking about?

1 Like
if (currentPotValue != oldPotValue) {
  oldPotValue = currentPotValue;
  call_a_function();
}

Yes, that was my first thought, but it makes the stepper rotate every time the potentiometer moves even a slight bit. I want for it to wait until the potentiometer stops moving, then for the stepper to make one smooth accelerated move

Same-same.

Try...

if (abs(oldPotValue - currentPotValue > deadband))
  call_a_function();

This is my code right now. I've added an extra stepper.moveTo(2048); to test something.

#include <AccelStepper.h>
#define HALFSTEP 8

#define POTENTIOMETER_PIN A0
int potentiometerValue = 0;
int previousPotentiometerValue = 0;
int movePosition = 0;

AccelStepper stepper(HALFSTEP, 8, 10, 9, 11);

void setup() {
  Serial.begin(9600);
  
  pinMode(POTENTIOMETER_PIN, INPUT);

  stepper.setMaxSpeed(1000.0);
  stepper.setAcceleration(100.0);
  stepper.setSpeed(300);
  stepper.moveTo(2048);
}

void loop() {
  potentiometerValue = constrain(analogRead(POTENTIOMETER_PIN), 8, 1015);

  if (abs(previousPotentiometerValue - potentiometerValue > 10)) {
    previousPotentiometerValue = potentiometerValue;
      if (stepper.distanceToGo() == 0) {
        map(movePosition, 8, potentiometerValue, -1024, 1024);
        stepper.moveTo(movePosition);
    }
    stepper.run();
  }
}

For some unknown - to me - reason, the stepper doesn't even move after the first call of moveTo. Any solutions? Telling just in case - it does move when i delete the contents of loop.

Besides, you did not call that right. I said:

So, it's not the same

It never will, so you need a deadband... and my guesses are not worth your time.

I implemented it

should this be < -10 ? because 9 is also < 10

another approach is

abs(potentiometerValue - previousPotentiometerValue) < 10

Servos can also provide smooth, non-rapid movement, with appropriate code.

There are many types and sizes of servo. In general, servos can handle more weight than steppers because they always include a gearbox, steppers usually don't. Your 28BYJ-48 does include a gearbox, which is why it is able to handle the weight, not the fact that it is a stepper.

That you could or should be using a servo as a servo, rather than using a stepper as a servo. Do you understand the advantages and drawbacks of each kind of motor?

there are other things wrong with your code

soulldn't this be != 0 ?

look this over

# include <AccelStepper.h>

const byte  PinPot = A0;

#define HALFSTEP 8
AccelStepper stepper (HALFSTEP, 8, 10, 9, 11);

int potVal;
int potValLst;

void loop ()
{
    potVal = analogRead (PinPot);

    if (abs (potVal - potValLst) > 5)  {
        Serial.println (potVal);
        potValLst = potVal;
        stepper.moveTo (potVal);
    }

    stepper.run ();
}

void setup () {
    Serial.begin (9600);

    pinMode (PinPot, INPUT);

    stepper.setMaxSpeed (1000.0);
    stepper.setAcceleration (100.0);
    stepper.setSpeed (300);
}

1 Like

Yes, I do, and I understand that I could have got down better with this idea. Unfortunately I'm stuck with a stepper because I've already built a plastic base, including a wheel matched perfectly with the output shaft. I have to figure out how to make it work with a stepper.

Yes, sorry, wrote this wrong.

distanceToGo()
long AccelStepper::distanceToGo () 
The distance from the current position to the target position.
Returns the distance from the current position to the target position in steps. Positive is clockwise from the current position. 

When the distance is equal to zero (stepper isn't moving), step to another position

but iif you haven't changed the target, distanceToGo() will always be zero.

it seems that you don't want to change the target by checking if (distanceToGo() == 0) but you only do this if there's a change in the pot position. Is there any reason to wait to reach the previous target before changing it?

the other thing is map(movePosition, 8, potentiometerValue, -1024, 1024); doesn't change the value of it's argument, it returns the "mapped" value. this should have been

movePosition = map(movePosition, 8, potentiometerValue, -1024, 1024);

wait, that's not right shouldn't it be

movePosition = map(potentiometerValue, 8, MaxPotentiometerValue, -1024, 1024);

misusing these various things is preventing the code from doing what you want. I've suggested a simpler version of code that should work and which you can modify with these other function

1 Like

Just noticed it as you were writing this and got to work. I've missed the concept of map, already fixed it. This is how it looks now:

#include <AccelStepper.h>
#define HALFSTEP 8

#define POTENTIOMETER_PIN A0
int potentiometerValue = 0;
int previousPotentiometerValue = 0;
int movePosition = 0;

AccelStepper stepper(HALFSTEP, 8, 10, 9, 11);

void setup() {
  Serial.begin(9600);
  
  pinMode(POTENTIOMETER_PIN, INPUT);

  stepper.setMaxSpeed(1000.0);
  stepper.setAcceleration(100.0);
  stepper.setSpeed(500);
}

void loop() {
  potentiometerValue = constrain(analogRead(POTENTIOMETER_PIN), 100, 900);

  if (abs(previousPotentiometerValue - potentiometerValue) > 50) {
      previousPotentiometerValue = potentiometerValue;
      movePosition = map(potentiometerValue, 100, 900, -1536 , 1536);
      stepper.moveTo(movePosition);
  }
  stepper.run();
}

It works perfectly now, so if you're looking for a accelerated stepper movement using a pot, here you go. I'd also changed some values (deadband, contrain and stepper's range), it seems to work better now. Thank you for your patience!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.