Changing target during motion (with ramping)

400 views
Skip to first unread message

Axel Hösl

unread,
Sep 9, 2014, 3:38:49 AM9/9/14
to accels...@googlegroups.com
At the moment I am trying to setup a prototype where one should be able to change the target of a motor motion dynamically (meaning while a motion from A to B is already executed). As far as my tests went with AccelStepper, I found that there is always a hard stop when changing the target (e.g. via a Serial command) and a new acceleration-motion-deceleration cycle is started afterwards. What I am trying to achieve is a change from a traget B to B' (in the easiest case B' is behind B).

I went into the source of AccelStepper but didn't find the part where the stop occurs. I am wondering whether this might be possible with AccelStepper at all or not. Do you think this doable with AccelStepper while not sacrificing the ramping? 

gregor

unread,
Sep 11, 2014, 10:03:15 AM9/11/14
to accels...@googlegroups.com
the stop probably occurs when reading the serial input.
i send my commands in patterns like "D motornumber target ", e.g. "D 1 100 ". without a whitespace at the end, my code stops for 1 second.

Mike McCauley

unread,
Sep 17, 2014, 9:02:54 PM9/17/14
to accels...@googlegroups.com
Hi,
AccelStepper is designed so that if you change the target position at any time
it should accel/decel to suit, not just stop.

Suspect the problem is in your code, which you have not posted so I can say no
more.

Cheers.
--
Mike McCauley VK4AMM mi...@airspayce.com
Airspayce Pty Ltd 9 Bulbul Place Currumbin Waters QLD 4223 Australia
http://www.airspayce.com
Phone +61 7 5598-7474

Axel Hösl

unread,
Sep 22, 2014, 5:35:31 AM9/22/14
to accels...@googlegroups.com
Thanks for the input the so far! I wasn't aware that the Serial command might trigger the stop. As my code became bigger over time due to the adding of features, I won't bug you with it and setup a new sketch where isolating that part, so that the issue can be looked at without the interferance of the other parts.

Thanks again!

Christian Thomsen

unread,
Oct 6, 2014, 5:32:11 PM10/6/14
to accels...@googlegroups.com
I think your troubles might be related to mine:

I want a two-wheeled differentially steered robot to not only perform some pre-programmed moves (AccelStepper is really good for that purpose!). I also want the motors to be able to change speed in mid-flow, so as to turn the robot left/right to steer away from obstacles.
For that purpose, i've setup a little test-sketch which reads a serial input from 0-9 (multiplied by 100) and sets the max-speed to that . It also sets a distant target, move(60000) to keep rolling...

void loop()
{
   if(Serial.available()) {
      // read the most recent byte (which will be from 0 to 255):
      int inSpeed = Serial.read()-48; // 48 is ascii '0'
      
      stepper1.setMaxSpeed(inSpeed*100);  
            if(inSpeed==0) { // '0': stop
         stepper1.stop();
      }
      else {
          stepper1.move(60000);
      }
   }
   stepper1.run();
}

This works nicely.
BUT:
AccelStepper can only accelerate, not decelerate in mid-flow. (is that why it's called "AccelStepper"?) in the function AccelStepper::computeNewSpeed() there's a feature to limit the top speed at the current _maxSpeed, and that causes a jolt when the speed suddenly changes, when you command a lower speed, not a smooth deceleration.
I made a copy of the library and implemented some changes which will allow this. The main changes were in AccelStepper::setMaxSpeed(float speed) and in AccelStepper::computeNewSpeed(), as well as adding a state-variable to indicate when a deceleration is in progress. Unfortunately, i've made quite some other changes to my version, as i only need a DRIVER-type stepper, and so i eliminated all code not related to driver-style interface.
These are my versions of those:
void AccelStepperDriver::setMaxSpeed(float speed) {
    if (_maxSpeed != speed) {
if(_direction == DIRECTION_CW) {
if(_speed > speed) { 
_isAccelerating = false;
}
else {
_isAccelerating = true;
}
}
else { // inverse if going ccw
if(-_speed > speed) { 
_isAccelerating = false;
}
else {
_isAccelerating = true;
}
}
_maxSpeed = speed;
_cmin = 1000000.0 / speed;
// Recompute _n from current speed and adjust speed if accelerating or cruising
if (_n > 0) {
_n = (long)((_speed * _speed) / (2.0 * _acceleration)); // Equation 16
if(_isAccelerating == false) {
_n = -_n;
}
computeNewSpeed();
}
    }
}

void AccelStepperDriver::computeNewSpeed() {
    long distanceTo = distanceToGo(); // +ve is clockwise from curent location
    long stepsToStop = (long)((_speed * _speed) / (2.0 * _acceleration)); // Equation 16

    if (distanceTo == 0 && stepsToStop <= 1) {
// We are at the target and its time to stop
_stepInterval = 0;
_speed = 0.0;
_n = 0;
return;
    }

    if (distanceTo > 0) {
// We are anticlockwise from the target
// Need to go clockwise from here, maybe decelerate now
if (_n > 0) {
// Currently accelerating, need to decel now? Or maybe going the wrong way?
if ((stepsToStop >= distanceTo) || _direction == DIRECTION_CCW) {
_n = -stepsToStop; // Start deceleration
}
}
else if (_n < 0) {
// Currently decelerating, need to accel again?
if(stepsToStop < distanceTo && _direction == DIRECTION_CW) {
long targetStepsToStop = (long)((_maxSpeed * _maxSpeed) / (2.0 * _acceleration)); // Equation 16
if(_isAccelerating || _n > -targetStepsToStop) { // braking to reach target speed complete
_n = -_n; // Start accceleration
_isAccelerating = true;
}
}
}
    }
    else if (distanceTo < 0) {
// We are clockwise from the target
// Need to go anticlockwise from here, maybe decelerate
if (_n > 0) {
// Currently accelerating, need to decel now? Or maybe going the wrong way?
if ((stepsToStop >= -distanceTo) || _direction == DIRECTION_CW) {
_n = -stepsToStop; // Start deceleration
}
}
else if (_n < 0) {
// Currently decelerating, need to accel again?
if ((stepsToStop < -distanceTo) && _direction == DIRECTION_CCW) {
long targetStepsToStop = (long)((_maxSpeed * _maxSpeed) / (2.0 * _acceleration)); // Equation 16
if(_isAccelerating || _n > -targetStepsToStop) { // braking to reach target speed complete
_n = -_n; // Start accceleration
_isAccelerating = true;
}
}
}
    }

    // Need to accelerate or decelerate
    if (_n == 0) {
// First step from stopped
_cn = _c0;
_direction = (distanceTo > 0) ? DIRECTION_CW : DIRECTION_CCW;
    }
    else {
// Subsequent step. Works for accel (n is +_ve) and decel (n is -ve).
_cn = _cn - ((2.0 * _cn) / ((4.0 * _n) + 1)); // Equation 13
if(_isAccelerating) { // allows deceleration to lower speeds
_cn = max(_cn, _cmin); 
}
    }
    _n++;
    _stepInterval = _cn;
    _speed = 1000000.0 / _cn;
    if (_direction == DIRECTION_CCW) {
_speed = -_speed;
}
}

I hope you can use these:

Cheers
Christian

Nick Suttell

unread,
Nov 7, 2014, 2:03:39 PM11/7/14
to accels...@googlegroups.com
So far this has worked nicely for me! Thank you very much for your adjustment, and big thanks to Mike for setting up the library!

Best Regards,
Nick
Reply all
Reply to author
Forward
0 new messages