pkerspe / ESP-FlexyStepper

This library is used to control one or more stepper motors from an ESP32 device. It is based on the FlexyStepper library by S.Reifel but provides some additional functionality
MIT License
152 stars 32 forks source link

Add support for angles, shortest path. #48

Open DanielCardiel opened 2 weeks ago

DanielCardiel commented 2 weeks ago

Add support for angles.

In the current iteration, if you move for example from rev 0.9 to .01, instead of moving the shortest part, it will go back doing the long direction.

now if I go from 259 to 1°, given the following code:

void StepperControl::moveStepperToAngle(float angle)
{
  // Ensure angle is within 0-360 range for safety
  angle = fmod(angle, 360.0);
  if (angle < 0)
  {
    angle += 360.0;
  }
  long steps = static_cast<long>((angle / 360.0) * STEPPER_STEPS_REV);

  Serial.println("Moving to: " + String(angle) + "°");
  Serial.println("Moving to position: " + String(steps));

  // Move to the calculated position in steps
  stepper.moveToPositionInSteps(steps);
}

It will go back on the long direction not the shortest path.

Something like this

void StepperControl::moveStepperToAngle(float angle)
{
  // Normalize the target angle to the range [0, 360)
  angle = fmod(angle, 360.0);
  if (angle < 0)
  {
    angle += 360.0;
  }

  // Convert target angle to steps
  long targetSteps = static_cast<long>((angle / 360.0) * STEPPER_STEPS_REV);

  // Get the current position in steps
  long currentSteps = stepper.getCurrentPositionInSteps();

  // Calculate the difference in steps, considering the shortest path
  long deltaSteps = targetSteps - currentSteps;

  // If delta is greater than half a revolution, adjust to take the shorter path
  if (deltaSteps > STEPPER_STEPS_REV / 2)
  {
    deltaSteps -= STEPPER_STEPS_REV;
  }
  else if (deltaSteps < -STEPPER_STEPS_REV / 2)
  {
    deltaSteps += STEPPER_STEPS_REV;
  }

  Serial.println("Moving directly to angle: " + String(angle) + "°");
  stepper.moveRelativeInSteps(deltaSteps);
}

void StepperControl::moveStepperToStepPosition(long stepPosition)
{
  // Normalize stepPosition to ensure it's within [0, STEPPER_STEPS_REV)
  stepPosition = stepPosition % STEPPER_STEPS_REV;
  if (stepPosition < 0)
  {
    stepPosition += STEPPER_STEPS_REV;
  }

  // Convert stepPosition to an angle (0 to 360 degrees)
  float angle = (stepPosition / static_cast<float>(STEPPER_STEPS_REV)) * 360.0;

  // Get the current position in steps
  long currentSteps = stepper.getCurrentPositionInSteps();

  // Calculate the shortest path in steps
  long deltaSteps = stepPosition - currentSteps;

  if (deltaSteps > STEPPER_STEPS_REV / 2)
  {
    deltaSteps -= STEPPER_STEPS_REV;
  }
  else if (deltaSteps < -STEPPER_STEPS_REV / 2)
  {
    deltaSteps += STEPPER_STEPS_REV;
  }

  Serial.println("Moving to step position: " + String(stepPosition) + " (angle: " + String(angle) + "°)");
  stepper.moveRelativeInSteps(deltaSteps);
}
pkerspe commented 2 weeks ago

Please Feel free to create a pull request, then I will review it. In general so far the library was more intended for linear movements but I do not see a reason to add such functions as long as they do not impact performance. For the blocking function set it should not make much difference, for the non blocking part this feature might be a bit more complex / involve more changes depending on the implementation route. But if all you need is basically a helper function to calculate an angle into steps, it should be no problem

DanielCardiel commented 2 weeks ago

Will do, I created the helper function, but I mean, if the library can have it from scratch. Would be nice :)

Will do later when I go back to my project :)