4
\$\begingroup\$

I have built a machine that juggles. An Arduino sends signals to stepper motor drivers that drive NEMA 23 size stepper motors.

juggling machine

Video of the machine: https://youtu.be/-9zD_8erkck

Currently, each arm makes one revolution and then pauses while the other arm makes one revolution. One arm starts before the other arm comes to a complete stop, the amount of overlap is captured by the variable stepover.

I would like to make the machine more consistent and run quieter with less vibration. How can I make it run smoother? Is there a way to do this where the hands will never come to a complete stop?

The stepper motors are running at 800 steps per revolution. I have tried to using more steps/rev for smoother operation, but the accelstepper library will not run the motors fast enough.

I have tried altering the values max_acceleration, max_speed, and stepover. I have not found a way to optimize these values.

#include <AccelStepper.h>
AccelStepper stepper1(AccelStepper::DRIVER, 9, 8);
AccelStepper stepper2(AccelStepper::DRIVER, 4, 3);

int start = 0;
int side = 0;
int max_speed = 6000;
int max_acceleration = 12000;
int stepover = 300;
int step_distance = 800;

void setup()
{
  stepper1.setMaxSpeed(max_speed);
  stepper2.setMaxSpeed(max_speed);
  stepper1.setAcceleration(1234);
  stepper2.setAcceleration(1234);
  stepper1.moveTo(600);
  stepper2.moveTo(-200);
}

void loop()
{
  // This code gets the arms in the right place before startup
  if (start == 0) {
    while (abs(stepper1.distanceToGo()) != 0) {
      stepper1.run();
    }
    while (abs(stepper2.distanceToGo()) != 0) {
      stepper2.run();
    }
    start = 1;
    stepper1.setAcceleration(max_acceleration);
    stepper2.setAcceleration(max_acceleration);
    delay(500);
  }

  // This code moves the left arm
  if (abs(stepper1.distanceToGo()) == 0
      and abs(stepper2.distanceToGo()) < stepover
      and side == 0) {
    stepper1.moveTo(step_distance + stepper1.currentPosition());
    side = 1;
  }

  // This code moves the right arm
  if (abs(stepper2.distanceToGo()) == 0
      and abs(stepper1.distanceToGo()) < stepover
      and side == 1) {
    stepper2.setCurrentPosition(0);
    stepper2.moveTo(step_distance);
    side = 0;
  }

  if (start == 1) {
    stepper2.run();
    stepper1.run();
  }
}
\$\endgroup\$
2
  • 1
    \$\begingroup\$ How many steps are available on the motor? Some datasheets I found seem to indicate 200 steps / revolution. Do you have a model with 800 steps? If it fits in memory, you could create an array, defining the desired speed for each step position. Your current logic would be something like uint8_t speed[800] = {255, 255, 255, ... 255, 0, 0, 0, 0, ...., 0};, either full speed or full stop. You could try to find the correct profile, and modify the values so that the motors is never completely stopping. \$\endgroup\$ Commented May 3, 2021 at 9:11
  • \$\begingroup\$ I am using stepper motors drivers that are capable of between 200 and 6400 steps per revolution. Computing the speeds and accelerations was too difficult for me, so I used the accelstepper library as a workaround. \$\endgroup\$ Commented May 3, 2021 at 15:00

1 Answer 1

2
\$\begingroup\$

Inside loop, you're checking if some code should be run before startup. You could simply move the corresponding code to setup, and be sure it's only run once:

#include <AccelStepper.h>
AccelStepper stepper1(AccelStepper::DRIVER, 9, 8);
AccelStepper stepper2(AccelStepper::DRIVER, 4, 3);

int side = 0;
int max_speed = 6000;
int max_acceleration = 12000;
int stepover = 300;
int step_distance = 800;

void setup() {
  stepper1.setMaxSpeed(max_speed);
  stepper2.setMaxSpeed(max_speed);
  stepper1.setAcceleration(1234);
  stepper2.setAcceleration(1234);
  stepper1.moveTo(600);
  stepper2.moveTo(-200);

  while (abs(stepper1.distanceToGo()) > 0) {
    stepper1.run();
  }
  while (abs(stepper2.distanceToGo()) > 0) {
    stepper2.run();
  }
  stepper1.setAcceleration(max_acceleration);
  stepper2.setAcceleration(max_acceleration);
  delay(500);
}

void loop() {
  // This code moves the left arm
  if (abs(stepper1.distanceToGo()) == 0 and abs(stepper2.distanceToGo()) < stepover and side == 0) {
    stepper1.moveTo(step_distance + stepper1.currentPosition());
    side = 1;
  }

  // This code moves the right arm
  if (abs(stepper2.distanceToGo()) == 0 and abs(stepper1.distanceToGo()) < stepover and side == 1) {
    stepper2.setCurrentPosition(0);
    stepper2.moveTo(step_distance);
    side = 0;
  }

  stepper2.run();
  stepper1.run();
}
  • abs cannot be negative, so it might be clearer to replace abs(...) != 0 by abs(...) > 0
  • AccelStepper::move(long relative) is defined as moveTo(_currentPos + relative); so you can probably replace your moveTo by move.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.