0

I am working on a project using an Arduino control a Stepper Motor. The motor drives a lead screw which moves coloured filters to specific positions along a linear track - forwards and backwards. The movements are triggered by another device that counts its revolutions (using a sensor. The Arduino reads the inputs and activates the motor on specific revs ie. at 10 move 70mm forwards, at 30 move 70mm backwards. I can control the Stepper to execute precise moves repeatedly one after another, independently of the counter. I can link the Arduino to the counter and switch on/off an LED at specified counts. But when I try to run the motors from the counter, it's triggered but only moves in tiny discontinuous steps, and only goes one way. Here is that Sketch below. Any help very welcome. Thanks.


// this constant won't change:
const int  buttonPin = 2;    // the pin that the pushbutton is attached to
const int ledPin = 7;       // the pin that the LED is attached to

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include <AccelStepper.h>

Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_StepperMotor *myMotor = AFMS.getStepper(200, 2);

void forwardstep1() {
  myMotor->onestep(FORWARD, DOUBLE);
}
void backwardstep1() {
  myMotor->onestep(BACKWARD, DOUBLE);
}

AccelStepper Astepper1(forwardstep1, backwardstep1);

void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);
  // initialize serial communication:
  Serial.begin(9600);
  AFMS.begin();  // create with the default frequency 1.6KHz
  //AFMS.begin(1000);  // OR with a different frequency, say 1KHz
  TWBR = ((F_CPU / 500000l) - 16) / 2; // Change the i2c clock to 400KHz
  Astepper1.setAcceleration(6000.0);
  Astepper1.setMaxSpeed(600);
  Astepper1.setSpeed(600);    // rpm
  //  while (switchIsOff) {
  //turn servo one direction -
  //tell servo this is 0
}

void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);
  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes: ");
      Serial.println(buttonPushCounter);
    } else {
      // if the current state is LOW then the button went from on to off:
      Serial.println("off");
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;

  if (buttonPushCounter == 10) {
    digitalWrite(ledPin, HIGH);
    Astepper1.moveTo(600);
    Astepper1.setSpeed(600);
    Astepper1.run();
  }

  if (buttonPushCounter == 30) {
    digitalWrite(ledPin, LOW);
    Astepper1.moveTo(200);
    Astepper1.setSpeed(600);
    Astepper1.run();
  }

  }
}
1
  • 1
    I think the problem is that Astepper.run() doesn't wait for the motor to reach it's target position. It is supposed to be called very frequently and will do a step, when it's the right time to, and returns when it is not. In your code it moves exactly until the counter is incremented the next time, because then you don't call the run method anymore. I'm currently not sure. Will write an answer, when I have time to check the source code
    – chrisl
    Apr 26, 2019 at 16:48

2 Answers 2

1

Thanks. Your description of the fault makes sense to me. As you point out blocking would be a problem as I need the counter to continue to be registering while the movement is being executed. I've revised the script as you suggest - inside the loop but outside the if statement - have I done as you meant? But the same problem occurs - the motor advances in single steps.


// this constant won't change:
const int  buttonPin = 2;    // the pin that the pushbutton is attached to
const int ledPin = 7;       // the pin that the LED is attached to

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include <AccelStepper.h>

Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_StepperMotor *myMotor = AFMS.getStepper(200, 2);

void forwardstep1() {
  myMotor->onestep(FORWARD, DOUBLE);
}
void backwardstep1() {
  myMotor->onestep(BACKWARD, DOUBLE);
}

AccelStepper Astepper1(forwardstep1, backwardstep1);

void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);
  // initialize serial communication:
  Serial.begin(9600);
  AFMS.begin();  // create with the default frequency 1.6KHz
  //AFMS.begin(1000);  // OR with a different frequency, say 1KHz
  TWBR = ((F_CPU / 500000l) - 16) / 2; // Change the i2c clock to 400KHz
  Astepper1.setAcceleration(6000.0);
  Astepper1.setMaxSpeed(600);
  Astepper1.setSpeed(600);    // rpm
  //  while (switchIsOff) {
  //turn servo one direction -
  //tell servo this is 0
}

void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);
  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes: ");
      Serial.println(buttonPushCounter);
    } else {
      // if the current state is LOW then the button went from on to off:
      Serial.println("off");
    }
    // save the current state as the last state, for next time through the loop
    lastButtonState = buttonState;

    if (buttonPushCounter == 10 ) {
      digitalWrite(ledPin, HIGH);
      Astepper1.moveTo(20000);
      Astepper1.setAcceleration(6000.0);
      Astepper1.setSpeed(600);
      //Astepper1.setSpeed(600);
      Astepper1.run();
    }
    Astepper1.run();//this command moved out of an 'if' statement, but still within the 'loop'

    if (buttonPushCounter == 30) {
      digitalWrite(ledPin, LOW);
      Astepper1.moveTo(200);
      Astepper1.setSpeed(600);
    }
    Astepper1.run();//this command moved out of an 'if' statement, but still within the 'loop'

  }
0

There are several run-like methods in the AccelStepper library.

The one you are using, run(), is intended to be called at EVERY pass through loop(), and it will only cause a step if one is necessary, based on the internal state of the library (i.e., current position, target position, acceleration profile, etc.) It is safe to call so often -- it will determine itself if there is any motion needed.

You could move the run() call to a place inside loop(), but outside of any if statements.

Alternatively, there is a runToPosition() function, which is blocking -- it will stop all execution of your code until the stepper is at the target position. This would be fine for your current code as posted, but if you wish to monitor the revolution counter also, then this would not be the best option to take.

Your Answer

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

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