Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exceeding final position when acceleration change in ramp #35

Open
tobo-123 opened this issue Dec 13, 2023 · 13 comments
Open

Exceeding final position when acceleration change in ramp #35

tobo-123 opened this issue Dec 13, 2023 · 13 comments
Labels
bug Something isn't working

Comments

@tobo-123
Copy link

tobo-123 commented Dec 13, 2023

Hello,

First of all, thank you for the great work, working with the library is a lot of fun, also because of the good documentation.

However, I am experiencing the following problem: I use the library to move a closed-loop servomotor back and forth between two fixed positions. I read in values for the speed and acceleration via two potentiometers, which I enter accordingly via setSpeedInStepsPerSecond and setAccelerationInStepsPerSecondPerSecond and setDecelerationInStepsPerSecondPerSecond. I use the startAsService - mode.

If I now lower the acceleration/deceleration value during the deceleration ramp before reaching the end point, the motor moves past the end point.

Is the error with me or is this a known behavior?

Best regards
tobo

@pkerspe
Copy link
Owner

pkerspe commented Dec 17, 2023

@tobo-123 as far as I can remember this is not a known behavior.
Maybe you can provide a demo sketch with the exact acceleration/deceleration values that cause the misbehaviour?

Can you also quantify the overshoot? How many steps and at what speed values are you overshooting?

I honestly never testet the behaviour if you change the acceleration/deceleration values when you are already in an acceleration/deceleration window.

@tobo-123
Copy link
Author

tobo-123 commented Dec 17, 2023

Hey, here is a sketch of the program. PotiSpeed and PotiAcc are integer values in the range of 1-100. The overshoot is pretty heavy, seems to depend on the amount of acceleration/deceleration reduction and is sometimes more >300 steps. My setup crashes in the limit switch so its hard to measure the steps.

This loop runs in an own task:

 for(;;) {
    stepper.setSpeedInStepsPerSecond(40000*PotiSpeed/100.0);
    stepper.setAccelerationInStepsPerSecondPerSecond(PotiSpeed*PotiSpeed*30+100*PotiAcc);
    stepper.setDecelerationInStepsPerSecondPerSecond(PotiSpeed*PotiSpeed*30+100*PotiAcc);

    if (stepper.getDistanceToTargetSigned() == 0)
    {  
      if (previousDirection == 1) {
        stepper.setTargetPositionInSteps(3000);
      }
      else {
        stepper.setTargetPositionInSteps(300);
      }
      previousDirection *= -1;
    }
  vTaskDelay(20);
  }

@tobo-123
Copy link
Author

I have been thinking a bit about the problem. Could it be that the following is happening?

Drawing

If the deceleration is changed in the ramp, the further deceleration takes place on a flatter curve, the original target x is overrun until the speed is 0 at position x', then there is a return movement to the original position. I may not be able to see this return movement because I am already in the limit switch.

Is that possible?

@pkerspe
Copy link
Owner

pkerspe commented Dec 18, 2023

Do you experience the overshooting problem only when you change from a higher deceleration to a lower deceleration value or also the other way round?

And just to be sure: if you do NOT change the deceleration value after deceleration has started, you are not experience overshooting, is that correct?

@tobo-123
Copy link
Author

Do you experience the overshooting problem only when you change from a higher deceleration to a lower deceleration value or also the other way round?

I did some additional testing today: The overshooting only occurs when lowering deceleration in the ramp. The final position seems to be reached exactly when I increase deceleration in the ramp.

And just to be sure: if you do NOT change the deceleration value after deceleration has started, you are not experience overshooting, is that correct?

Yes, when I don’t change acceleration/deceleration values everything is fine and the positions are reached exactly.

I did another test and changed my program a bit:

 for(;;) {
    stepper.setSpeedInStepsPerSecond(40000*PotiSpeed/100.0);
    stepper.setAccelerationInStepsPerSecondPerSecond(PotiSpeed*PotiSpeed*30+100*PotiAcc);
    stepper.setDecelerationInStepsPerSecondPerSecond(PotiSpeed*PotiSpeed*30+100*PotiAcc);

    if (stepper.getDistanceToTargetSigned() == 0)
    {  
      if (previousDirection == 1) {
        stepper.setTargetPositionInSteps(2000);
      }
      else {
      }
      previousDirection *= -1;
    }
  vTaskDelay(20);
  }

Now I only go to position 2000 which gives me more length on my axis to see whats happening without reaching the limit switch. I saw the behavior I tried to sketch in my little drawing: When lowering deceleration in the ramp, I overshoot the position, the motor decelerates slower, stops, starts to move in the opposite direction and finally stops at the planned position.

@petervanderwalt
Copy link

petervanderwalt commented Dec 28, 2023

Basic move like

stepper_1.setStepsPerMillimeter(400);
stepper_1.moveRelativeInMillimeters(32);

Also overshoots for me

In my setup I have

stepper_1.connectToPins(STEP_1, DIR_1);
stepper_2.connectToPins(STEP_2, DIR_2);

// Defaults
stepper_1.setSpeedInStepsPerSecond(SPEED_IN_STEPS_PER_SECOND);
stepper_1.setAccelerationInStepsPerSecondPerSecond(ACCELERATION_IN_STEPS_PER_SECOND);
stepper_1.setDecelerationInStepsPerSecondPerSecond(DECELERATION_IN_STEPS_PER_SECOND);

stepper_2.setSpeedInStepsPerSecond(SPEED_IN_STEPS_PER_SECOND);
stepper_2.setAccelerationInStepsPerSecondPerSecond(ACCELERATION_IN_STEPS_PER_SECOND);
stepper_2.setDecelerationInStepsPerSecondPerSecond(DECELERATION_IN_STEPS_PER_SECOND);

stepper_1.startAsService(0);
stepper_2.startAsService(0);

Values are

const int SPEED_IN_STEPS_PER_SECOND = 25600;
const int ACCELERATION_IN_STEPS_PER_SECOND = 25600;
const int DECELERATION_IN_STEPS_PER_SECOND = 25600;

I suspect its something I am doing wrong, because Example7_DualAxis works for me. But i want to use blocking move instead of setTargetPosition

[edit]
stepper_1.setTargetPositionRelativeInMillimeters(distanceToMoveInMillimeters);
while (stepper_1.getDistanceToTargetSigned() != 0)
{
Serial.printf("Stepper position: %i\n", stepper_1.getCurrentPositionInSteps());
}

Works correctly, instead of stepper_1.moveRelativeInMillimeters(32); (using the while to block)

@pkerspe
Copy link
Owner

pkerspe commented Dec 28, 2023

@petervanderwalt sorry, I am not sure what you want to achieve and works or doesn't. You speak about blocking moves (I assume you mean the blocking functions in the library) but you are starting the library as a service (which is non blocking).
Also you while loop consumes a lot of you cycles since you pump out data at highest possible frequency on the serial port in parallel. Not sure how that interferes with the library and potential jitter in the movement.
Maybe you can explain more in detail what works and what doesn't and which of the two steppers you are initializing overshoots

@tobo-123
Copy link
Author

tobo-123 commented Jan 9, 2024

Hi pkerspe, any news on my issue? I guess it's not necessarily a bug of the library, but a behavior to be aware of. I think it would be good to point out this behavior in the documentation. It would be great to have a function that checks whether the target can be reached safely with a new decelleration value and returns this as true/false. Then the user could prohibit writing new decelleration values. Would that be feasible?

@pkerspe
Copy link
Owner

pkerspe commented Jan 9, 2024

Sorry for the delay. Currently on sick leave and was to busy with other tasks the last weeks. I guess it should be easy to provide a function that returns if a ramp is active, will check this week!

@pkerspe
Copy link
Owner

pkerspe commented Jan 9, 2024

Can you try using getCurrentVelocityInStepsPerSecond() and comparing to your set max speed? That way at least you should see if you are in a ramp

@tobo-123
Copy link
Author

tobo-123 commented Jan 9, 2024

Thanks for your quick reply. Comparing current velocity with set speed is a good idea, I'll try that. But I don't think it completely solves the problem. As far as I understand DeterminePeriodOfNextStep(), a reduction of deceleration shortly before the calculated start of the ramp should also lead to overshooting. Therefore, a function that performs a calculation would be best.

@tobo-123
Copy link
Author

tobo-123 commented Jan 9, 2024

Here my idea of a new version of the setDecelerationInStepsPerSecondPerSecondNew:

bool ESP_FlexyStepper::setDecelerationInStepsPerSecondPerSecondNew(
    float decelerationInStepsPerSecondPerSecond)
{
  long distanceToTarget_Unsigned;
  long decelerationDistance_InSteps;
  float currentStepPeriodSquared;

  distanceToTarget_Unsigned = abs(targetPosition_InSteps - currentPosition_InSteps);

  currentStepPeriodSquared = currentStepPeriod_InUS * currentStepPeriod_InUS;
  decelerationDistance_InSteps = (long)round(
      5E11 / (decelerationInStepsPerSecondPerSecond * currentStepPeriodSquared));

  if (distanceToTarget_Unsigned > decelerationDistance_InSteps) {
  	deceleration_InStepsPerSecondPerSecond = decelerationInStepsPerSecondPerSecond;
  	deceleration_InStepsPerUSPerUS = deceleration_InStepsPerSecondPerSecond / 1E12;
 	return true;
  }
  else {
	return false;
  }

}

It only "accepts" new values if the newly calculated ramp is not longer than the current distance to target. What do you think, can this work?

@pkerspe pkerspe added the bug Something isn't working label Jan 14, 2024
@IdxCarles
Copy link

Hi,

What I am seeing is that if that the target decc is diferent than de acceleration, then is giving the target complete when it lacks some pulses to finish.

PROGRAM sample to go 20 rev to one direction and 20 revolutions to the other direction
//SETUP
stepper.setStepsPerRevolution(200);
stepper.setSpeedInRevolutionsPerSecond(5);
stepper.setAccelerationInRevolutionsPerSecondPerSecond(1); //+> + +
stepper.setDecelerationInRevolutionsPerSecondPerSecond(2); //
//MOVE
stepper.moveToPositionInRevolutions(20);
Serial.print(stepper.getCurrentPositionInRevolutions());
delay(1000);
//MOVE OTHER DIRECTION
stepper.moveToPositionInRevolutions(-20);
Serial.print(stepper.getCurrentPositionInRevolutions());
delay(1000);

See the osciloscope signal: The system is still sending Pulses when is sending the stepper to the other direction.
(This happens only when acc/decc)

imatge

Really thank's,

Carles

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants