Motor keep moving to previus moveTo after stop

517 views
Skip to first unread message

Zohar

unread,
Oct 21, 2021, 9:19:56 AM10/21/21
to accelstepper
I just started to use AccelStepper and found a strange behavior and could not find an example how to overcome it.

I start to move the motor in one direction and then stop it due to a sensor (or time out in the example).

Now I set a new moveTo destination, in the other direction. When I allow it to run again the motor continues the first movement and only after reaching the original destination it will turn to the other way and run to the new destination!

This is bad, as the motor keep running into my mechanical limit.

 

I thought that the .stop or the new .moveTo will clear the original destination. But it does not.

How can I make the motor change direction after the stop (And not continue the first movement)



#include <AccelStepper.h>
AccelStepper stepper1(1, 4, 3);

void setup() {
  Serial.begin(9600);         // Setup Serial Monitor
  Serial.println("Hi");

  stepper1.setMaxSpeed(600);
  stepper1.setAcceleration(800);
  stepper1.setCurrentPosition(0);

  stepper1.moveTo(-500);
  for (int i = 0; i <= 200; i++) {
    stepper1.run();     
    delay(10);
  }  
  stepper1.stop();     
  Serial.print("  current pos=");   Serial.println (stepper1.currentPosition());
  delay(1500);

  stepper1.moveTo(0);
  while ( stepper1.distanceToGo() != 0 ) {
    stepper1.run();
    Serial.println (stepper1.currentPosition());
  }
  Serial.print("  current pos=");   Serial.println (stepper1.currentPosition());
}

void loop() {
}

Zohar

unread,
Oct 21, 2021, 11:14:49 AM10/21/21
to accelstepper
I found out that if I add:
stepper1.setCurrentPosition( stepper1.currentPosition() );

After the stop command then the motor will forget the last point and next move will be as needed.
Is there a better command that have the same effect?

gjgsm...@gmail.com

unread,
Oct 21, 2021, 5:10:07 PM10/21/21
to accelstepper
I've only had a quick look but I suspect your 'stop()' command is not working as you expected.

'stop()' does not actually stop your stepper, it only sets a target to stop the stepper as quickly as possible. You have to then command the stepper to run to that target by calling 'stepper1.run();' after the stop command instead of the line- 'stepper1.setCurrentPosition( stepper1.currentPosition() );'.

Geoff

Zohar

unread,
Oct 22, 2021, 10:00:37 AM10/22/21
to accelstepper
But I relly wish to end the first moveTo command, as the real triger is the a limit sensor.
If the motor will continue the first moveTo it will bump into the mechanicl stop.

gjgsm...@gmail.com

unread,
Oct 23, 2021, 1:08:34 AM10/23/21
to accelstepper
Try this .... 
On my stepper setup (800 steps/rev) and with these speed and acceleration settings it takes 33 steps to come to a complete stop.


#include <AccelStepper.h>

// Define a stepper and the pins it will use
#define DIR_A A0 // Define  Stepper PINS
#define PUL_A A1

AccelStepper stepper1(AccelStepper::DRIVER, PUL_A, DIR_A); // Assign Pins

void setup() {
  Serial.begin(9600);         // Setup Serial Monitor
  Serial.println("Hi");

  stepper1.setMaxSpeed(400);
  stepper1.setAcceleration(2500);
 //  stepper1.setCurrentPosition(0);   Not needed as 'on boot' current positions are always zero.

  stepper1.moveTo(-500);
  while(stepper1.isRunning()) {
  stepper1.run();  
  if( stepper1.currentPosition() == -250 ) {
  stepper1.stop();
  stepper1.run();
  }
 }
      
  Serial.print("  current pos=");   Serial.println (stepper1.currentPosition());
  delay(1500);

  stepper1.moveTo(0);
  while ( stepper1.distanceToGo() != 0 ) {
    stepper1.run();
  }
  Serial.print("  current pos=");   Serial.println (stepper1.currentPosition());
}

void loop() {
}

gjgsm...@gmail.com

unread,
Oct 23, 2021, 1:14:58 AM10/23/21
to accelstepper
Here's another example with no acceleration and hence no stopping lag. There are a few factors like inertia which may come into play when stopping the stepper suddenly which could cause missed steps.


#include <AccelStepper.h>

// Define a stepper and the pins it will use
#define DIR_A A0              // Define  Stepper PINS
#define PUL_A A1

AccelStepper stepper1(AccelStepper::DRIVER, PUL_A, DIR_A); // Assign Pins


void setup() {
 
  Serial.begin(9600);         // Setup Serial Monitor
  Serial.println("Hi");

  stepper1.setMaxSpeed(1600);
  
  stepper1.moveTo(-700);

  while(stepper1.isRunning()) {
  stepper1.setSpeed(100);
  stepper1.runSpeedToPosition();
  
    if(stepper1.currentPosition() == -500) {
  
    delay(1000);

    stepper1.moveTo(0);
    stepper1.setSpeed(1600);
   
      while(stepper1.distanceToGo()!= 0) {
      stepper1.runSpeedToPosition();
      }
    }
  }
}

void loop() {
}

Jim Larson

unread,
Oct 26, 2021, 10:04:03 PM10/26/21
to accelstepper
The idea of moving quickly until an end stop is hit, then stopping immediately, seems to me like driving your car rapidly toward a brick will and expecting to stop it just as the bumper touches the wall. Maybe not the best plan given the laws of physics! I would tend to place the end sensor a distance before the hard stop, or anticipate the sensor by knowing when to slow down so that an attempt at a very sudden stop from quick motion is avoided.
Let's consider two cases.  
First, let's assume we know where the hard stop is, relative to the start (0) position. Say it's at -600. When we get close, say at -450, we will slow down. We could also just set a target of -580, then we would stop there and could runSpeed slowly to the limit. But that seems obvious and easy.
So, second, let's assume we really don't know where the limit is, then there must be some minimal space before the hard stop. We'll go full speed until we hit the end sensor and stop as quickly as we can.
Here's the plan:
- set up an interrupt to fire when the end stop is hit. (For this demo, we'll use an second counter in the loop to put out a pulse.) This interrupt will put us in the stopNow state.
- start the motor running to a position so it accelerates to the target speed.
- when the motor gets to speed, use runSpeed to keep it going. Position is tracked, but the target is ignored.
- when we enter stopNow state, use stop() and runToPosition() to stop.
- set a new target of 0 (or -currentPosition) and run to it (accelerates and decelerates). The interrupt should be ignored.
My motor is controlled by an A4988 driver using step and direction in full-step mode. The code runs on an arduino Uno.

Here is the code:
/*
   Uno sketch to drive a bipolar stepper motor using an a4988
   driver (or similar) and the AccelStepper library.
   This code is a response to a Forum question.
   10/27/21   -jkl
*/
// Include the AccelStepper Library
#include <AccelStepper.h>
#include <elapsedMillis.h>

// Define pin connections
const int dirPin = 4;
const int stepPin = 5;
const int sensorPin = 9;  // used as an end stop sensor output - driven by a timer
// hook to pin D2 - or can drive D2 directly (tie low, then disconnect to cause interrupt)

// define the time limit to run before stopping if using sensorPin
const int timeLimit = 10;  // number of seconds

// State definitions
#define RSPD 01
#define RJSTR 02
#define RUN_HOME 03
#define STOP_NOW 04
// State variable
volatile int state;   // must survive interrupts

// Creates an instance
AccelStepper myStepper(AccelStepper::DRIVER, stepPin, dirPin);

elapsedMillis printTime;

volatile int enabFlag = 0;  // controls the end stop sensor interrupt

void setup() {
  Serial.begin(115200);
  attachInterrupt(0, rising, RISING);
  enabFlag = 1; // enable the sensor interrupt
  pinMode (sensorPin, OUTPUT);
  state = RJSTR;   // initial state is run, just run
  // set the maximum speed, acceleration factor,
  // initial speed and the target position
  myStepper.setMaxSpeed(400.);
  myStepper.setAcceleration(50.0);
  myStepper.moveTo(-1000);
}
int lCount = 0; // elapsed seconds
void loop() {
  float mSpeed;
  if (printTime >= 1000) {    // happens once per second
    printTime = 0;
    lCount++;
    mSpeed = myStepper.speed();
    Serial.print(mSpeed);
    Serial.print("  ");
    Serial.println(myStepper.currentPosition());
    switch (state) {
      case RSPD:
        if (lCount >= timeLimit) {
          digitalWrite(sensorPin,HIGH);    // This will trigger interrupt
        }
        break;
      case RJSTR:
        if (mSpeed <= -200.0) {
          state = RSPD;   // switch to run speed state when target speed is reached
        }
        break;
      case RUN_HOME:
      case STOP_NOW:    // this should never execute.
        break;
    }
  }
  switch (state) {    // happens each loop - about 70KHz
    case RSPD:
      myStepper.runSpeed();
      break;
    case RJSTR:
    case RUN_HOME:
      myStepper.run();
      break;
    case STOP_NOW:
      digitalWrite(sensorPin,LOW);    // removes interrupt signal
      myStepper.setAcceleration(200.0);  // this makes motor stop much quicker!
      myStepper.stop();
      myStepper.runToPosition();  // brings to a stop!
      myStepper.moveTo(0);  // now return to home position
      myStepper.setAcceleration(50.0);  // slow motor acceleration back down
      //myStepper.move(-myStepper.currentPosition()); // This should work also
      state = RUN_HOME;
      break;
  }
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++ Interrupt service routine +++++++++++++++++++++++++++++
//  Come here if rising edge on D2.
//  If enable flag is true, enter state STOP_NOW
void rising() {
  if (enabFlag == 1) {
    state = STOP_NOW;
    enabFlag = 0;
  }
}

Reply all
Reply to author
Forward
0 new messages