Problems with lag controlling stepper motor velocity with load cell.

Hello!
This is my first post, however I have spent a lot of time here searching for examples and solutions for various of my projects.
I have done a lot of projects, however I consider myself as begginer as most of the time all I was doing was just copy/pasting code to suit for my needs.
However a lot of things changed in last project as I can not find solution online, that is why I am hoping you can help me.

The plan is to use load cell, to measure force in positive and negtive dirrection and the stepper motor should lincrease the velocity as the force increases. Naturaly when there is no force pressent the motor should stop. Also I would like to put in the code, that when the push button is pressed, the stepper motor returns to initial position

For my setup i am using:

  • 20kg load cell (primaraly used in weight scales)
  • HX711 load cell amplifier
  • arduino nano
  • stepper motor driver Gecko G213V (max 7.5A, 80V), running at 5A and 36V
  • Nema 24 stepper motor stepper motor site
  • 36V PSU link

There is no problem with connection as everything is working as I wrote the code.
I know exactly that there is a problem in my code I just do not know how to write it to behave it as I want.

In current code stepper behaves as it should until about 50RPM, after that, when I increase the force and therefore stepper velocity it starts to stop between each loop, updating the new velocity only then starting the motor again. That way I can only reach about 300 RPMs as everytime stepper stops it starts with full velocity without acceleration and naturaly stalls. I would like to get the stepper up to 1000 RPM which I know it is achivable as I am using accelStepper libary to return stepper to initial position.
I know that this is not the right way to achive what I want since stepper.step is a blocking function and it is not right way to achive continous motion.
I would much rather use accellStepper libary with non blocking function but so far it was worse than before, every time I have tried.
I have tried with move function and then runSpeed wich I think should give non blocking continous motion, but all I get is even more lag.

So here is my code with stepper libary for velocity control that is working the best so far:

//code for turning Stepper motor CW/CWW with load cell measurments for controlling direction and velocity, and push button switch for return to initial position


#include <Stepper.h>
#include "AccelStepper.h"
#include "HX711.h"


//Stepper

#define dir_pin 5   // Pin 5 connected to Direction pin
#define step_pin 6  // Pin 6 connected to Steps pin
#define SLEEP 7     // Pin 7 connected to SLEEP pin

//Load cell values
#define calibration_factor -100 //This value is obtained using the SparkFun_HX711_Calibration sketch  load cell:575 rocka:33
#define DOUT  11
#define CLK  12



//For returning to first position after button is pressed

volatile boolean forceDetected = false ;  // false initial state
volatile boolean rotationdirection;  // CW or CCW rotation
const int PinSW = 2;  // Reading Push Button switch

int StepperPosition = 0;  // initial Stepper Motor Position
const int stepsPerRevolution = 2000; // steps per revolution: motor: 200 steps   microsteping: 10

Stepper stepper(stepsPerRevolution, dir_pin, step_pin);
AccelStepper accStepper(AccelStepper::DRIVER, step_pin, dir_pin);
HX711 scale;




//load cell value, if force is detected
float val = 0;
int velocity;
const float positionZero = 0;
const float flimit = 50; //limit when there is enough force to start motion
const float minforce = -5000;
const float noforce = 0; //value when there is no force present
const float maxforce = 5000; //maximal value of force
const float minvelocity = 1; //minimal motor velocity
const float maxvelocity = 200; //maximal motor velocity
volatile boolean middle = true; // define middle position



// Interrupt routine runs if load cell detects force

void rotarydetect ()  {
  //delay(1);  // delay for Debouncing

  val = scale.get_units();
  if (val > noforce + flimit) { //if force is greater than minimum triger ammount, turn motor CCW

    rotationdirection = true;
    forceDetected = true;
    middle = false;
  }
  else if (val < noforce - flimit) { //if force is smaller than minimum triger ammount in negative value, turn motor CW

    rotationdirection = false;
    forceDetected = true;
    middle = false;
  }
  else {
    middle = true;

  }


}


void setup ()  {

  pinMode(dir_pin, OUTPUT);
  pinMode(step_pin, OUTPUT);
  pinMode(SLEEP, OUTPUT);
  digitalWrite(SLEEP, LOW);  // Wake up Driver
  delay(5);  // Wait for Driver wake up


  pinMode(PinSW, INPUT_PULLUP);

  accStepper.setMaxSpeed(20000);  // Set speed for accelstepper
  accStepper.setAcceleration(10000);  // Acceleration for accelstepper

  scale.begin(DOUT, CLK);
  scale.set_scale(calibration_factor); //This value is obtained by using the SparkFun_HX711_Calibration sketch
  scale.tare(); //Assuming there is no weight on the scale at start up, reset the scale to 0
}



void loop ()
//button return to zero
{

  if ((int) digitalRead(PinSW) == 0) {   // check if button is pressed,
    if (StepperPosition == 0) {  // check if button was already pressed
    }

    else {
      if (StepperPosition > 0) { // Stepper was moved CW

        // set stepper to the new calculated position
        accStepper.setSpeed(20000);
        accStepper.move(-StepperPosition);
        accStepper.runToPosition();
      }

      else {
        //  Do until Motor position is back to ZERO

        // set stepper to the new calculated position
        accStepper.setSpeed(20000);
        accStepper.move(StepperPosition);
        accStepper.runToPosition();
      }

      StepperPosition = 0; // Reset position to ZERO after moving motor back
    }
  }

  //move stepper if force on load cell is detected
  rotarydetect();

  //stepper control (currently this is the best as I can get. I would rather use accelStepper non blocking functions,
  // but I get worse results. Currently this code runs OK till about 50 RPM
  if (forceDetected == true && middle == false)  {
    forceDetected = false;  // do NOT repeat IF loop until new Force detected

    // Which direction to move Stepper motor
    if (rotationdirection) { // Move DOWN

      velocity = map(val, noforce, maxforce, minvelocity, maxvelocity);  // Map velocity value as force increases

      stepper.setSpeed(velocity);
      stepper.step(5 * velocity);

      StepperPosition = StepperPosition + ((5 * velocity) / 4); //because stepper libary gives position in RPM,
      //I have to recalculate value in order to accelStepper libary return to initial position in button is pressed

    }


    if (!rotationdirection) { // Move motor UP

      velocity = map(val, noforce, minforce, minvelocity, maxvelocity);  // Map velocity value as force increases

      stepper.setSpeed(velocity);
      stepper.step(-(5 * velocity));

      StepperPosition = StepperPosition - ((5 * velocity) / 4); //because stepper libary gives position in RPM,
      //I have to recalculate value in order to accelStepper libary return to initial position in button is pressed

    }
  }
}

Entire sketch is commented in order to explain as much as I can. The part that is causing problems is the lower part after stepper control part, everything else is working as I want it to.

I am really desperate, since I am strugling with this for several days now and I do not know how to proceed further.
Any advice or solution will be deeply apreciated. Thank you.
Dominik

You should not be mixing the Stepper library and the AccelStepper library - just use AccelStepper as it is a lot more competent.

...R

2000 steps per rev * 1000 RPM = 33333 steps per second, or a step every 30 microSeconds. IIRC, AccelStepper can only do about 4000 with a 16MHz Arduino.

JCA34F:
2000 steps per rev * 1000 RPM = 33333 steps per second, or a step every 30 microSeconds. IIRC, AccelStepper can only do about 4000 with a 16MHz Arduino.

To my mind that suggests the need for a faster microprocessor. Presumably it will be expected to do other stuff as well as control the motor.

And, I agree that AccelStepper is not appropriate if using a 16MHz Arduino. My point in Reply #1 was to stick to a single library. I have no idea what the standard Stepper library is capable of.

I believe some Forum users have achieved high step rates with this Simple Stepper Code which does not use any library. And it is not difficult to create simple acceleration code

...R

Hi!
Thank you for quick reply.

Robin2:
You should not be mixing the Stepper library and the AccelStepper library - just use AccelStepper as it is a lot more competent.

...R

That is my goal, to use just accelstepper libary, however with stepper libary currently I get best results.

JCA34F:
2000 steps per rev * 1000 RPM = 33333 steps per second, or a step every 30 microSeconds. IIRC, AccelStepper can only do about 4000 with a 16MHz Arduino.

Let's stop for a moment and focus more on smooth running. acheiving high speed is my secondary goal. My main focus so far is to produce a code that creates motion without stopping motor between every force reading.

Robin2:
To my mind that suggests the need for a faster microprocessor. Presumably it will be expected to do other stuff as well as control the motor.

And, I agree that AccelStepper is not appropriate if using a 16MHz Arduino. My point in Reply #1 was to stick to a single library. I have no idea what the standard Stepper library is capable of.

I believe some Forum users have achieved high step rates with this Simple Stepper Code which does not use any library. And it is not difficult to create simple acceleration code

...R

Could you please suggest a board that is capable of acheiving higher speeds, so for my example 33333 steps per second? or some other way to achive this (my driver has only 10 microstep option)?

I will look into your links and try to figure out something useful. But is this also the problem causing lag? If yes cold you explain why?

Hi,
What is the application?
What is the source of the force and what is the stepper turning?

It sounds like a power assisted positioning system, like power assisted steering.
Do you need a stepper?
Wouldn't a motor and encoder be better for speed and its rotational position?
You would still get the information, so pressing the center button would still be counting from the encoder back to a redetermined position.

Tom..... :slight_smile:

TomGeorge:
Hi,
What is the application?
What is the source of the force and what is the stepper turning?

It sounds like a power assisted positioning system, like power assisted steering.
Do you need a stepper?
Wouldn't a motor and encoder be better for speed and its rotational position?
You would still get the information, so pressing the center button would still be counting from the encoder back to a redetermined position.

Tom..... :slight_smile:

The source of force, is the amount you push on the load cellwith your hand, so encoder is out of the question.

Basicly it is as you have guesed it it is power assisted system. The more you push on the rod, the more motor increases velocity, making it feel that it is helping you more.

I am not completely certain that I need stepper, however I see no other more economical solution as I need really high torques (about 2,5Nm on motor).

Hi,
You use the encoder to keep track of the motor position, because you said in post #1;

Also I would like to put in the code, that when the push button is pressed, the stepper motor returns to initial position

With a DC motor that is how you will know how many turns the motor has taken so it can return to "initial position".
What mechanical device have you got the stepper connected to to assist?
You talk about velocity assisting a force!!!!!!!

Can you post a basic diagram of how you have your hardware connected?

Thanks.. Tom.. :slight_smile:

dominikus123:
Let's stop for a moment and focus more on smooth running. acheiving high speed is my secondary goal.

[....]

Could you please suggest a board that is capable of acheiving higher speeds, so for my example 33333 steps per second? or some other way to achive this (my driver has only 10 microstep option)?

These seem to be contradictory requests :slight_smile:

There are several Arduino boards using much faster microprocessors. Also there are boards using ESP8266 and ESP32 microprocessors that can be programmed with the Arduino IDE. Note, however, that the faster boards all (I think) work at 3.3v rather than 5v.

My main focus so far is to produce a code that creates motion without stopping motor between every force reading.

Have you written a short program that allows you to measure the time taken to get a force reading?

...R

TomGeorge:
Hi,
You use the encoder to keep track of the motor position, because you said in post #1;

With a DC motor that is how you will know how many turns the motor has taken so it can return to "initial position".
What mechanical device have you got the stepper connected to to assist?
You talk about velocity assisting a force!!!!!!!

Can you post a basic diagram of how you have your hardware connected?

Thanks.. Tom.. :slight_smile:

I do not need that precise motion for now, so there is no need for encoder. I am just counting steps and than go back the same number of steps when I push the button.

You have a diagram in attachment.

Robin2:
Have you written a short program that allows you to measure the time taken to get a force reading?

...R

No I have not, because I do not have need to play with timing. What I want to do, is start the motor and update its velocity acording to force readings, while motor is still running if there is some delay I do not mind.

1 Like

dominikus123:
No I have not, because I do not have need to play with timing. What I want to do, is start the motor and update its velocity acording to force readings, while motor is still running if there is some delay I do not mind.

I don't see it like that.

You need to produce steps for the motor at regular intervals. In between some of the steps you need to read the force sensor. If the time taken to read the force sensor is too long it will upset the timing of the production of steps.

...R

Isn’t the default refresh speed of a hx711 board like 10hz?

That’s pretty good for measuring weight of something, but to use as positional control maybe you could look into how to switch it too 80hz?

What would happen if you rewired your setup so that you could vary what microsteping mode you were in and then simply “switch stepping” when you had a large force vs a small force on the load cell.

Hi,
OPS diagram.


Thanks.. Tom.. :slight_smile:

Nevermind the step-switching.
That Gecko G213V datasheet states it needs to be powered down to change stepping.

Maybe this is simple, did I read your notes correctly.
This part of the code works to move the stepper fast.

        accStepper.setSpeed(20000);
        accStepper.move(StepperPosition);
        accStepper.runToPosition();

But this code is not resulting in fast movement?

       velocity = map(val, noforce, maxforce, minvelocity, maxvelocity);  // Map velocity value as force increases

      stepper.setSpeed(velocity);
      stepper.step(5 * velocity);

Sure seems it would be possible to rewrite the later.

Robin2:
I don't see it like that.

You need to produce steps for the motor at regular intervals. In between some of the steps you need to read the force sensor. If the time taken to read the force sensor is too long it will upset the timing of the production of steps.

...R

Ok, I see now where are you going... So if I understand correctly, even if I use non blocking command I will still need to squeeze the force reading between one of the steps, So basicly it is the same if I use blocking or non blocking comand as there wont be enough time to recalculate force when step increment becomes smaller when velocity increases. Please correct me if I am wrong.
I have now switched to full step mode and I am able to get to about 200 RPM without interupts betwen force reading updates. However if I run the accStepper.runToNewPosition() command which drives the stepper with current max set speed without interupts I come to about 600 RPM (I am getting close to my 1000 RPM wish :slight_smile: ) .

So my next logical step is to switch to faster board. Am I right? Does lets say 4 times faster processor also give me 4 times faster speeds regarding step output?

Slumpert:
Nevermind the step-switching.
That Gecko G213V datasheet states it needs to be powered down to change stepping.

Maybe this is simple, did I read your notes correctly.
This part of the code works to move the stepper fast.

        accStepper.setSpeed(20000);

accStepper.move(StepperPosition);
        accStepper.runToPosition();




But this code is not resulting in fast movement?



velocity = map(val, noforce, maxforce, minvelocity, maxvelocity);  // Map velocity value as force increases

stepper.setSpeed(velocity);
      stepper.step(5 * velocity);



Sure seems it would be possible to rewrite the later.

I am not sure if I understood your message. You are trying to say to change the lower part of the code with same as it is in first part?
Would you be so nice to show an example so we understand eachother 100%?

dominikus123:
Ok, I see now where are you going... So if I understand correctly, even if I use non blocking command I will still need to squeeze the force reading between one of the steps, So basicly it is the same if I use blocking or non blocking comand as there wont be enough time to recalculate force when step increment becomes smaller when velocity increases. Please correct me if I am wrong.

You are correct if you are saying that if the force calculation takes a certain fixed time and if the interval between steps need to be shorter than that (for a higher motor speed) you will run into a problem.

I don't know what you had in mind when you wrote "blocking or non blocking".

I have now switched to full step mode and I am able to get to about 200 RPM without interupts betwen force reading updates. However if I run the accStepper.runToNewPosition() command which drives the stepper with current max set speed without interupts I come to about 600 RPM (I am getting close to my 1000 RPM wish

I can't make sense of that in the context of the force sensor - where does it fit in? And why are "interrupts" mentioned?

RPM is not a useful measure. Stick to steps per second.

...R

By blocking I mean that it does not allow to compute any other functions until it completes the blocking command.

About second statement....
By interrupts I mean the small pause between stepper movements that is caused because of slower processor.
The second part is not directly tied to force measurements, but the max speed, when I push the button to return to initial position is faster, as I can drive it back with constant speed with acceleration. If I compare that to case when I also use load cell in velocity mapping I get smaller speeds because between every new velocity update, there is small stop that is causing motor to start again with max speed without acceleration therefore stalling much quicker than it would normally if using acceleration.

dominikus123:
By blocking I mean that it does not allow to compute any other functions until it completes the blocking command.

I know what blocking means. What I did not understand is the reference to "blocking or non blocking". Perhaps you were thinking of two alternative pieces of code that you have not shared with us?

About second statement....
By interrupts I mean the small pause between stepper movements that is caused because of slower processor.
The second part is not directly tied to force measurements, but the max speed, when I push the button to return to initial position is faster, as I can drive it back with constant speed with acceleration..

The word "interrupt" has a very specific technical meaning in microprocessor programming and I don't think you intend that meaning - which makes the use of the word confusing.

If I compare that to case when I also use load cell in velocity mapping I get smaller speeds because between every new velocity update, there is small stop that is causing motor to start again with max speed without acceleration therefore stalling much quicker than it would normally if using acceleration

Sorry, but I don't understand that either. Keep in mind that you are thinking about this problem for hours compared to my 2 or 3 minutes. So you need to explain things in great detail if we are to keep up with your thought process.

What is causing the small stop? How long (in microseconds) is the small stop? Why does the motor have to start again at max speed?

...R