Controlling the speed and direction of rotation of a large stepper using a single potentiometer

Hi all,
I'd like to control the direction of rotation and speed of a large stepper motor by using a single potentiometer.
The motor is a Nema 23 3Nm motor which is being driven by a DM542 driver.

I've successfully managed to get the motor wired and working correctly using an Arduino Uno and some test code.
The real-world application is winding the lead screw on the X-axis on a small milling machine which is normally controlled by a hand wheel.
I'd like to arrange it so that when the pot is in the central position the motor is stopped.
When turned a small amount e.g. positive from the central position, the motor turns slowly clockwise. When the pot is turned further positive the speed will increase up to the maximum amount at the end of the pot’s travel.
Retuning the pot to the central position at any point will stop rotation.

Turning the pot in the e.g. negative direction will mirror the above rotation, but this time in the counter clockwise direction.

Any suggestions would be most welcome.

There are plenty of tutorials that will help you get started. A web search for "arduino read potentiometer" turned up this as the first hit:

https://docs.arduino.cc/learn/electronics/potentiometer-basics/

I would suggest implementing a dead band, to ensure zero speed. Otherwise it is a simple matter of mapping the analog value to a speed.

1 Like

Hello,

Did you succeded in changing the rotation speed of the motor as you wish?
How do you generate the pulses?

To do you what you want to do, you'll need to check the maximal value that you can read from the POT. For now, I guess it is going to be from 0 to 1023

Let's say the middle point is 512. You'll have to set an interval in which you considere to be at the Stand by position. Otherwise it is going to be really difficult to reach exactly 512.

For example, if the value is between 450 and 574, then you do nothing

Otherwise, you read the value and substract 512 (half of the maximal value). Let's say you measured 200. The result will then be 200 - 512 = -312.

You will know that you have to turn in CCW because of the minus (or you can invert the logic). To set the speed, let's say the speed goes from 0 to 10 (arbitrary)

So you need to scale the absolute value of the result of your calcul (here the -312). you can use the map() function for this.

speed = map(abs(result), 0, 512, 0, 0);

Hope I'm making myself clear enough

1 Like

output

 pot    526, spd      0, dly      0, dir  0 Stop
 pot    526, spd      0, dly      0, dir  0 Stop
 pot    514, spd      0, dly      0, dir  0 Stop
 pot    495, spd     -1, dly   1000, dir -1 Rev
 pot    481, spd     -1, dly   1000, dir -1 Rev
 pot    473, spd     -1, dly   1000, dir -1 Rev
 pot    494, spd     -1, dly   1000, dir -1 Rev
 pot    512, spd      0, dly      0, dir  0 Stop
 pot    531, spd      0, dly      0, dir  0 Stop
 pot    551, spd      0, dly      0, dir  0 Stop
 pot    575, spd      1, dly   1000, dir  1 For
 pot    590, spd      1, dly   1000, dir  1 For
 pot    609, spd      1, dly   1000, dir  1 For
 pot    635, spd      2, dly    500, dir  1 For
 pot    656, spd      2, dly    500, dir  1 For
 pot    680, spd      3, dly    333, dir  1 For
 pot    701, spd      3, dly    333, dir  1 For
 pot    718, spd      4, dly    250, dir  1 For
 pot    739, spd      4, dly    250, dir  1 For
 pot    749, spd      4, dly    250, dir  1 For
// speed control pot

const int PotMax = 1023;
const int SpdMax = 10;
char s [90];

// -----------------------------------------------------------------------------
void
loop ()
{
    int pot = analogRead (A0);
    int spd = map(pot, 0, PotMax, -SpdMax, SpdMax);
    int dly = spd == 0 ? 0 : 1000/abs(spd);
    int dir = spd == 0 ? 0 : (spd > 0 ? 1 : -1);

    sprintf (s, " pot %6d, spd %6d, dly %6d, dir %2d %s",
        pot, spd, dly, dir, dir == 0 ? "Stop" : (dir > 0 ? "For" : "Rev") );
    Serial.println (s);

    delay (1500);        // slow prints
}

// -----------------------------------------------------------------------------
void
setup (void)
{
    Serial.begin (9600);
}

Consider a Rotary Encoder instead.

So are you happy with that or...? You post it without saying anything

Many thanks for all the suggestions.
I like the dead band idea.
I have plenty of pots available so choose that rout for now.
I'll ask the question (pls don't shout) can someone write this code for me for a small amout of $$.?

There's a section of the forum for that very thing: Jobs and Paid Consultancy.

???

Was this a lie???

Why would you need someone to write the code for you if this is already working?

No lies here. I've simply copied code to prove to myself that the motor, comtroller, Arduino are wired correctly and able to control the motor.

This (clearly) is not my area of expertise and i've got to the point of being able to make the motor work but my lack of expertise to get the system working.

Is it too much trouble to learn the basics? It would take about six lines of code to read the pot and steer the motor.

And you have not even bothered to read and follow the forum rules about posting the information needed by forum members to help.

Could you post here the code you used to control the stepper motor pls

not sure if you're using any libraries. If not, you might have a loop that steps the motor.

It seems you need to determine the direction and speed from the pot and step the motor in the desired direction with an appropriate delay (1000/spd) OR not step if if the speed is zero

This is the code I copied/pasted to prove to myself that all the parts worked:

// Written By: Jeremy Fielding. Watch the instructional video here. https://youtu.be/QMgckRoRy38

#include <AccelStepper.h>

//Defining pins
int Stepper1Pulse = 5; // Pulse or step pin
int Stepper1Direction = 6; // Direction pin
int Stepper2Pulse = 7;
int Stepper2Direction = 8;
int speedpot = A0; // Potentiometer
int positionpot = A1;

//defining terms

int Motor1speed = 0;
int Motor2position = 0;
int speedmin = 0; //pulses per second
int speedmax = 4000; //pulses per second
int positionmax = 1600;
AccelStepper step1(1, Stepper1Pulse, Stepper1Direction);
AccelStepper step2(1, Stepper2Pulse, Stepper2Direction);

void setup() {

step1.setMaxSpeed (speedmax);
step1.setSpeed(0);
step1.setAcceleration(1000);
step2.setMaxSpeed (10000);
step2.setSpeed(5000);
step2.setAcceleration(10000);
pinMode(Stepper1Pulse, OUTPUT);
pinMode(Stepper1Direction, OUTPUT);
pinMode(Stepper2Pulse, OUTPUT);
pinMode(Stepper2Direction, OUTPUT);
digitalWrite(Stepper1Pulse, LOW);
digitalWrite(Stepper1Direction, LOW);
digitalWrite(Stepper2Pulse, LOW);
digitalWrite(Stepper2Direction, HIGH);

}

void loop() {

Motor1speed = map((analogRead(speedpot)),0,1023,speedmin,speedmax);
step1.setSpeed(Motor1speed);
step1.runSpeed();
Motor2position = map((analogRead(positionpot)),0,1023,0,positionmax);
step2.moveTo(Motor2position);
step2.run();

}

Use the code tags pls :slight_smile:

the problem with this approach is the pot specified a position not a speed

try below with code above

    if (0 <= dly)  {
        step1.step (dir);
        delay (dly);
    }

I need to go now but will be back tomorrow..